···352352 If one selects "m," this driver can be loaded using the following353353 command: 354354 $>modprobe acpi_memhotplug 355355+356356+config ACPI_SBS357357+ tristate "Smart Battery System (EXPERIMENTAL)"358358+ depends on X86 && I2C359359+ depends on EXPERIMENTAL360360+ default y361361+ help362362+ This driver adds support for the Smart Battery System.363363+ Depends on I2C (Device Drivers ---> I2C support)364364+ A "Smart Battery" is quite old and quite rare compared365365+ to today's ACPI "Control Method" battery.366366+355367endif # ACPI356368357369endmenu
···5050MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);5151MODULE_LICENSE("GPL");52525353+extern struct proc_dir_entry *acpi_lock_ac_dir(void);5454+extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);5555+5356static int acpi_ac_add(struct acpi_device *device);5457static int acpi_ac_remove(struct acpi_device *device, int type);5558static int acpi_ac_open_fs(struct inode *inode, struct file *file);···283280284281static int __init acpi_ac_init(void)285282{286286- int result = 0;283283+ int result;287284288285289289- acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);286286+ acpi_ac_dir = acpi_lock_ac_dir();290287 if (!acpi_ac_dir)291288 return -ENODEV;292292- acpi_ac_dir->owner = THIS_MODULE;293289294290 result = acpi_bus_register_driver(&acpi_ac_driver);295291 if (result < 0) {296296- remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);292292+ acpi_unlock_ac_dir(acpi_ac_dir);297293 return -ENODEV;298294 }299295···304302305303 acpi_bus_unregister_driver(&acpi_ac_driver);306304307307- remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);305305+ acpi_unlock_ac_dir(acpi_ac_dir);308306309307 return;310308}
+7-6
drivers/acpi/battery.c
···5959MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);6060MODULE_LICENSE("GPL");61616262+extern struct proc_dir_entry *acpi_lock_battery_dir(void);6363+extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);6464+6265static int acpi_battery_add(struct acpi_device *device);6366static int acpi_battery_remove(struct acpi_device *device, int type);6467···755752756753static int __init acpi_battery_init(void)757754{758758- int result = 0;755755+ int result;759756760760-761761- acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);757757+ acpi_battery_dir = acpi_lock_battery_dir();762758 if (!acpi_battery_dir)763759 return -ENODEV;764764- acpi_battery_dir->owner = THIS_MODULE;765760766761 result = acpi_bus_register_driver(&acpi_battery_driver);767762 if (result < 0) {768768- remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);763763+ acpi_unlock_battery_dir(acpi_battery_dir);769764 return -ENODEV;770765 }771766···775774776775 acpi_bus_unregister_driver(&acpi_battery_driver);777776778778- remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);777777+ acpi_unlock_battery_dir(acpi_battery_dir);779778780779 return;781780}
+131
drivers/acpi/cm_sbs.c
···11+/*22+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License as published by66+ * the Free Software Foundation; either version 2 of the License, or (at77+ * your option) any later version.88+ *99+ * This program is distributed in the hope that it will be useful, but1010+ * WITHOUT ANY WARRANTY; without even the implied warranty of1111+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1212+ * General Public License for more details.1313+ *1414+ * You should have received a copy of the GNU General Public License along1515+ * with this program; if not, write to the Free Software Foundation, Inc.,1616+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.1717+ *1818+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1919+ */2020+2121+#include <linux/kernel.h>2222+#include <linux/module.h>2323+#include <linux/init.h>2424+#include <linux/acpi.h>2525+#include <linux/types.h>2626+#include <linux/proc_fs.h>2727+#include <linux/seq_file.h>2828+#include <acpi/acpi_bus.h>2929+#include <acpi/acpi_drivers.h>3030+#include <acpi/acmacros.h>3131+#include <acpi/actypes.h>3232+#include <acpi/acutils.h>3333+3434+ACPI_MODULE_NAME("cm_sbs")3535+#define ACPI_AC_CLASS "ac_adapter"3636+#define ACPI_BATTERY_CLASS "battery"3737+#define ACPI_SBS_COMPONENT 0x000800003838+#define _COMPONENT ACPI_SBS_COMPONENT3939+static struct proc_dir_entry *acpi_ac_dir;4040+static struct proc_dir_entry *acpi_battery_dir;4141+4242+static struct semaphore cm_sbs_sem;4343+4444+static int lock_ac_dir_cnt = 0;4545+static int lock_battery_dir_cnt = 0;4646+4747+struct proc_dir_entry *acpi_lock_ac_dir(void)4848+{4949+5050+ down(&cm_sbs_sem);5151+ if (!acpi_ac_dir) {5252+ acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);5353+ }5454+ if (acpi_ac_dir) {5555+ lock_ac_dir_cnt++;5656+ } else {5757+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,5858+ "Cannot create %s\n", ACPI_AC_CLASS));5959+ }6060+ up(&cm_sbs_sem);6161+ return acpi_ac_dir;6262+}6363+6464+EXPORT_SYMBOL(acpi_lock_ac_dir);6565+6666+void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)6767+{6868+6969+ down(&cm_sbs_sem);7070+ if (acpi_ac_dir_param) {7171+ lock_ac_dir_cnt--;7272+ }7373+ if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {7474+ remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);7575+ acpi_ac_dir = 0;7676+ }7777+ up(&cm_sbs_sem);7878+}7979+8080+EXPORT_SYMBOL(acpi_unlock_ac_dir);8181+8282+struct proc_dir_entry *acpi_lock_battery_dir(void)8383+{8484+8585+ down(&cm_sbs_sem);8686+ if (!acpi_battery_dir) {8787+ acpi_battery_dir =8888+ proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);8989+ }9090+ if (acpi_battery_dir) {9191+ lock_battery_dir_cnt++;9292+ } else {9393+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,9494+ "Cannot create %s\n", ACPI_BATTERY_CLASS));9595+ }9696+ up(&cm_sbs_sem);9797+ return acpi_battery_dir;9898+}9999+100100+EXPORT_SYMBOL(acpi_lock_battery_dir);101101+102102+void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)103103+{104104+105105+ down(&cm_sbs_sem);106106+ if (acpi_battery_dir_param) {107107+ lock_battery_dir_cnt--;108108+ }109109+ if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param110110+ && acpi_battery_dir) {111111+ remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);112112+ acpi_battery_dir = 0;113113+ }114114+ up(&cm_sbs_sem);115115+ return;116116+}117117+118118+EXPORT_SYMBOL(acpi_unlock_battery_dir);119119+120120+static int __init acpi_cm_sbs_init(void)121121+{122122+123123+ if (acpi_disabled)124124+ return 0;125125+126126+ init_MUTEX(&cm_sbs_sem);127127+128128+ return 0;129129+}130130+131131+subsys_initcall(acpi_cm_sbs_init);
+406
drivers/acpi/i2c_ec.c
···11+/*22+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)33+ *44+ * Copyright (c) 2002, 2005 Ducrot Bruno55+ * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)66+ *77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License as published by99+ * the Free Software Foundation version 2.1010+ */1111+1212+#include <linux/version.h>1313+#include <linux/module.h>1414+#include <linux/slab.h>1515+#include <linux/kernel.h>1616+#include <linux/stddef.h>1717+#include <linux/sched.h>1818+#include <linux/init.h>1919+#include <linux/i2c.h>2020+#include <linux/acpi.h>2121+#include <linux/delay.h>2222+2323+#include "i2c_ec.h"2424+2525+#define xudelay(t) udelay(t)2626+#define xmsleep(t) msleep(t)2727+2828+#define ACPI_EC_HC_COMPONENT 0x000800002929+#define ACPI_EC_HC_CLASS "ec_hc_smbus"3030+#define ACPI_EC_HC_HID "ACPI0001"3131+#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver"3232+#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"3333+3434+#define _COMPONENT ACPI_EC_HC_COMPONENT3535+3636+ACPI_MODULE_NAME("acpi_smbus")3737+3838+static int acpi_ec_hc_add(struct acpi_device *device);3939+static int acpi_ec_hc_remove(struct acpi_device *device, int type);4040+4141+static struct acpi_driver acpi_ec_hc_driver = {4242+ .name = ACPI_EC_HC_DRIVER_NAME,4343+ .class = ACPI_EC_HC_CLASS,4444+ .ids = ACPI_EC_HC_HID,4545+ .ops = {4646+ .add = acpi_ec_hc_add,4747+ .remove = acpi_ec_hc_remove,4848+ },4949+};5050+5151+/* Various bit mask for EC_SC (R) */5252+#define OBF 0x015353+#define IBF 0x025454+#define CMD 0x085555+#define BURST 0x105656+#define SCI_EVT 0x205757+#define SMI_EVT 0x405858+5959+/* Commands for EC_SC (W) */6060+#define RD_EC 0x806161+#define WR_EC 0x816262+#define BE_EC 0x826363+#define BD_EC 0x836464+#define QR_EC 0x846565+6666+/*6767+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model6868+ */6969+7070+#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */7171+#define ACPI_EC_SMB_STS 0x01 /* status */7272+#define ACPI_EC_SMB_ADDR 0x02 /* address */7373+#define ACPI_EC_SMB_CMD 0x03 /* command */7474+#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */7575+#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */7676+#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */7777+#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */7878+7979+#define ACPI_EC_SMB_STS_DONE 0x808080+#define ACPI_EC_SMB_STS_ALRM 0x408181+#define ACPI_EC_SMB_STS_RES 0x208282+#define ACPI_EC_SMB_STS_STATUS 0x1f8383+8484+#define ACPI_EC_SMB_STATUS_OK 0x008585+#define ACPI_EC_SMB_STATUS_FAIL 0x078686+#define ACPI_EC_SMB_STATUS_DNAK 0x108787+#define ACPI_EC_SMB_STATUS_DERR 0x118888+#define ACPI_EC_SMB_STATUS_CMD_DENY 0x128989+#define ACPI_EC_SMB_STATUS_UNKNOWN 0x139090+#define ACPI_EC_SMB_STATUS_ACC_DENY 0x179191+#define ACPI_EC_SMB_STATUS_TIMEOUT 0x189292+#define ACPI_EC_SMB_STATUS_NOTSUP 0x199393+#define ACPI_EC_SMB_STATUS_BUSY 0x1A9494+#define ACPI_EC_SMB_STATUS_PEC 0x1F9595+9696+#define ACPI_EC_SMB_PRTCL_WRITE 0x009797+#define ACPI_EC_SMB_PRTCL_READ 0x019898+#define ACPI_EC_SMB_PRTCL_QUICK 0x029999+#define ACPI_EC_SMB_PRTCL_BYTE 0x04100100+#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06101101+#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08102102+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a103103+#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c104104+#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d105105+#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a106106+#define ACPI_EC_SMB_PRTCL_PEC 0x80107107+108108+/* Length of pre/post transaction sleep (msec) */109109+#define ACPI_EC_SMB_TRANSACTION_SLEEP 1110110+#define ACPI_EC_SMB_ACCESS_SLEEP1 1111111+#define ACPI_EC_SMB_ACCESS_SLEEP2 10112112+113113+static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)114114+{115115+ u8 val;116116+ int err;117117+118118+ err = ec_read(smbus->base + address, &val);119119+ if (!err) {120120+ *data = val;121121+ }122122+ xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);123123+ return (err);124124+}125125+126126+static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)127127+{128128+ int err;129129+130130+ err = ec_write(smbus->base + address, data);131131+ return (err);132132+}133133+134134+static int135135+acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,136136+ char read_write, u8 command, int size,137137+ union i2c_smbus_data *data)138138+{139139+ struct acpi_ec_smbus *smbus = adap->algo_data;140140+ unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };141141+ int i;142142+143143+ if (read_write == I2C_SMBUS_READ) {144144+ protocol = ACPI_EC_SMB_PRTCL_READ;145145+ } else {146146+ protocol = ACPI_EC_SMB_PRTCL_WRITE;147147+ }148148+ pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;149149+150150+ switch (size) {151151+152152+ case I2C_SMBUS_QUICK:153153+ protocol |= ACPI_EC_SMB_PRTCL_QUICK;154154+ read_write = I2C_SMBUS_WRITE;155155+ break;156156+157157+ case I2C_SMBUS_BYTE:158158+ if (read_write == I2C_SMBUS_WRITE) {159159+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);160160+ }161161+ protocol |= ACPI_EC_SMB_PRTCL_BYTE;162162+ break;163163+164164+ case I2C_SMBUS_BYTE_DATA:165165+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);166166+ if (read_write == I2C_SMBUS_WRITE) {167167+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);168168+ }169169+ protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;170170+ break;171171+172172+ case I2C_SMBUS_WORD_DATA:173173+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);174174+ if (read_write == I2C_SMBUS_WRITE) {175175+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);176176+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,177177+ data->word >> 8);178178+ }179179+ protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;180180+ break;181181+182182+ case I2C_SMBUS_BLOCK_DATA:183183+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);184184+ if (read_write == I2C_SMBUS_WRITE) {185185+ len = min_t(u8, data->block[0], 32);186186+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);187187+ for (i = 0; i < len; i++)188188+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,189189+ data->block[i + 1]);190190+ }191191+ protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;192192+ break;193193+194194+ case I2C_SMBUS_I2C_BLOCK_DATA:195195+ len = min_t(u8, data->block[0], 32);196196+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);197197+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);198198+ if (read_write == I2C_SMBUS_WRITE) {199199+ for (i = 0; i < len; i++) {200200+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,201201+ data->block[i + 1]);202202+ }203203+ }204204+ protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;205205+ break;206206+207207+ case I2C_SMBUS_PROC_CALL:208208+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);209209+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);210210+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);211211+ protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;212212+ read_write = I2C_SMBUS_READ;213213+ break;214214+215215+ case I2C_SMBUS_BLOCK_PROC_CALL:216216+ protocol |= pec;217217+ len = min_t(u8, data->block[0], 31);218218+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);219219+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);220220+ for (i = 0; i < len; i++)221221+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,222222+ data->block[i + 1]);223223+ protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;224224+ read_write = I2C_SMBUS_READ;225225+ break;226226+227227+ default:228228+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "229229+ "Unsupported transaction %d\n", size));230230+ return (-1);231231+ }232232+233233+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);234234+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);235235+236236+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);237237+238238+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {239239+ xudelay(500);240240+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);241241+ }242242+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {243243+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);244244+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);245245+ }246246+ if ((~temp[0] & ACPI_EC_SMB_STS_DONE)247247+ || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {248248+ return (-1);249249+ }250250+251251+ if (read_write == I2C_SMBUS_WRITE) {252252+ return (0);253253+ }254254+255255+ switch (size) {256256+257257+ case I2C_SMBUS_BYTE:258258+ case I2C_SMBUS_BYTE_DATA:259259+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);260260+ break;261261+262262+ case I2C_SMBUS_WORD_DATA:263263+ case I2C_SMBUS_PROC_CALL:264264+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);265265+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);266266+ data->word = (temp[1] << 8) | temp[0];267267+ break;268268+269269+ case I2C_SMBUS_BLOCK_DATA:270270+ case I2C_SMBUS_BLOCK_PROC_CALL:271271+ len = 0;272272+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);273273+ len = min_t(u8, len, 32);274274+ case I2C_SMBUS_I2C_BLOCK_DATA:275275+ for (i = 0; i < len; i++)276276+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,277277+ data->block + i + 1);278278+ data->block[0] = len;279279+ break;280280+ }281281+282282+ return (0);283283+}284284+285285+static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)286286+{287287+288288+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |289289+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |290290+ I2C_FUNC_SMBUS_BLOCK_DATA |291291+ I2C_FUNC_SMBUS_PROC_CALL |292292+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |293293+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);294294+}295295+296296+static struct i2c_algorithm acpi_ec_smbus_algorithm = {297297+ .smbus_xfer = acpi_ec_smb_access,298298+ .functionality = acpi_ec_smb_func,299299+};300300+301301+static int acpi_ec_hc_add(struct acpi_device *device)302302+{303303+ int status;304304+ unsigned long val;305305+ struct acpi_ec_hc *ec_hc;306306+ struct acpi_ec_smbus *smbus;307307+308308+ if (!device) {309309+ return -EINVAL;310310+ }311311+312312+ ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);313313+ if (!ec_hc) {314314+ return -ENOMEM;315315+ }316316+ memset(ec_hc, 0, sizeof(struct acpi_ec_hc));317317+318318+ smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);319319+ if (!smbus) {320320+ kfree(ec_hc);321321+ return -ENOMEM;322322+ }323323+ memset(smbus, 0, sizeof(struct acpi_ec_smbus));324324+325325+ ec_hc->handle = device->handle;326326+ strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);327327+ strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);328328+ acpi_driver_data(device) = ec_hc;329329+330330+ status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);331331+ if (ACPI_FAILURE(status)) {332332+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));333333+ kfree(ec_hc->smbus);334334+ kfree(smbus);335335+ return -EIO;336336+ }337337+338338+ smbus->ec = acpi_driver_data(device->parent);339339+ smbus->base = (val & 0xff00ull) >> 8;340340+ smbus->alert = val & 0xffull;341341+342342+ smbus->adapter.owner = THIS_MODULE;343343+ smbus->adapter.algo = &acpi_ec_smbus_algorithm;344344+ smbus->adapter.algo_data = smbus;345345+346346+ if (i2c_add_adapter(&smbus->adapter)) {347347+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,348348+ "EC SMBus adapter: Failed to register adapter\n"));349349+ kfree(smbus);350350+ kfree(ec_hc);351351+ return -EIO;352352+ }353353+354354+ ec_hc->smbus = smbus;355355+356356+ printk(KERN_INFO PREFIX "%s [%s]\n",357357+ acpi_device_name(device), acpi_device_bid(device));358358+359359+ return AE_OK;360360+}361361+362362+static int acpi_ec_hc_remove(struct acpi_device *device, int type)363363+{364364+ struct acpi_ec_hc *ec_hc;365365+366366+ if (!device) {367367+ return -EINVAL;368368+ }369369+ ec_hc = acpi_driver_data(device);370370+371371+ i2c_del_adapter(&ec_hc->smbus->adapter);372372+ kfree(ec_hc->smbus);373373+ kfree(ec_hc);374374+375375+ return AE_OK;376376+}377377+378378+static int __init acpi_ec_hc_init(void)379379+{380380+ int result;381381+382382+ result = acpi_bus_register_driver(&acpi_ec_hc_driver);383383+ if (result < 0) {384384+ return -ENODEV;385385+ }386386+ return 0;387387+}388388+389389+static void __exit acpi_ec_hc_exit(void)390390+{391391+ acpi_bus_unregister_driver(&acpi_ec_hc_driver);392392+}393393+394394+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)395395+{396396+ return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));397397+}398398+399399+EXPORT_SYMBOL(acpi_get_ec_hc);400400+401401+module_init(acpi_ec_hc_init);402402+module_exit(acpi_ec_hc_exit);403403+404404+MODULE_LICENSE("GPL");405405+MODULE_AUTHOR("Ducrot Bruno");406406+MODULE_DESCRIPTION("ACPI EC SMBus driver");
+23
drivers/acpi/i2c_ec.h
···11+/*22+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)33+ *44+ * Copyright (c) 2002, 2005 Ducrot Bruno55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License as published by88+ * the Free Software Foundation version 2.99+ */1010+1111+struct acpi_ec_smbus {1212+ struct i2c_adapter adapter;1313+ union acpi_ec *ec;1414+ int base;1515+ int alert;1616+};1717+1818+struct acpi_ec_hc {1919+ acpi_handle handle;2020+ struct acpi_ec_smbus *smbus;2121+};2222+2323+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
+1-3
drivers/acpi/numa.c
···259259{260260 int pxm, node = -1;261261262262- ACPI_FUNCTION_TRACE("acpi_get_node");263263-264262 pxm = acpi_get_pxm(handle);265263 if (pxm >= 0)266264 node = acpi_map_pxm_to_node(pxm);267265268268- return_VALUE(node);266266+ return node;269267}270268EXPORT_SYMBOL(acpi_get_node);
+1766
drivers/acpi/sbs.c
···11+/*22+ * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $)33+ *44+ * Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>55+ *66+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License as published by1010+ * the Free Software Foundation; either version 2 of the License, or (at1111+ * your option) any later version.1212+ *1313+ * This program is distributed in the hope that it will be useful, but1414+ * WITHOUT ANY WARRANTY; without even the implied warranty of1515+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1616+ * General Public License for more details.1717+ *1818+ * You should have received a copy of the GNU General Public License along1919+ * with this program; if not, write to the Free Software Foundation, Inc.,2020+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.2121+ *2222+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~2323+ */2424+2525+#include <linux/init.h>2626+#include <linux/module.h>2727+#include <linux/moduleparam.h>2828+#include <linux/kernel.h>2929+#include <linux/proc_fs.h>3030+#include <linux/seq_file.h>3131+#include <asm/uaccess.h>3232+#include <linux/acpi.h>3333+#include <linux/i2c.h>3434+#include <linux/delay.h>3535+3636+#include "i2c_ec.h"3737+3838+#define DEF_CAPACITY_UNIT 33939+#define MAH_CAPACITY_UNIT 14040+#define MWH_CAPACITY_UNIT 24141+#define CAPACITY_UNIT DEF_CAPACITY_UNIT4242+4343+#define REQUEST_UPDATE_MODE 14444+#define QUEUE_UPDATE_MODE 24545+4646+#define DATA_TYPE_COMMON 04747+#define DATA_TYPE_INFO 14848+#define DATA_TYPE_STATE 24949+#define DATA_TYPE_ALARM 35050+#define DATA_TYPE_AC_STATE 45151+5252+extern struct proc_dir_entry *acpi_lock_ac_dir(void);5353+extern struct proc_dir_entry *acpi_lock_battery_dir(void);5454+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);5555+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);5656+5757+#define ACPI_SBS_COMPONENT 0x000800005858+#define ACPI_SBS_CLASS "sbs"5959+#define ACPI_AC_CLASS "ac_adapter"6060+#define ACPI_BATTERY_CLASS "battery"6161+#define ACPI_SBS_HID "ACPI0002"6262+#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver"6363+#define ACPI_SBS_DEVICE_NAME "Smart Battery System"6464+#define ACPI_SBS_FILE_INFO "info"6565+#define ACPI_SBS_FILE_STATE "state"6666+#define ACPI_SBS_FILE_ALARM "alarm"6767+#define ACPI_BATTERY_DIR_NAME "BAT%i"6868+#define ACPI_AC_DIR_NAME "AC0"6969+#define ACPI_SBC_SMBUS_ADDR 0x97070+#define ACPI_SBSM_SMBUS_ADDR 0xa7171+#define ACPI_SB_SMBUS_ADDR 0xb7272+#define ACPI_SBS_AC_NOTIFY_STATUS 0x807373+#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x807474+#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x817575+7676+#define _COMPONENT ACPI_SBS_COMPONENT7777+7878+#define MAX_SBS_BAT 47979+#define MAX_SMBUS_ERR 18080+8181+ACPI_MODULE_NAME("acpi_sbs");8282+8383+MODULE_AUTHOR("Rich Townsend");8484+MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");8585+MODULE_LICENSE("GPL");8686+8787+static struct semaphore sbs_sem;8888+8989+#define UPDATE_MODE QUEUE_UPDATE_MODE9090+/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */9191+#define UPDATE_INFO_MODE 09292+#define UPDATE_TIME 609393+#define UPDATE_TIME2 09494+9595+static int capacity_mode = CAPACITY_UNIT;9696+static int update_mode = UPDATE_MODE;9797+static int update_info_mode = UPDATE_INFO_MODE;9898+static int update_time = UPDATE_TIME;9999+static int update_time2 = UPDATE_TIME2;100100+101101+module_param(capacity_mode, int, CAPACITY_UNIT);102102+module_param(update_mode, int, UPDATE_MODE);103103+module_param(update_info_mode, int, UPDATE_INFO_MODE);104104+module_param(update_time, int, UPDATE_TIME);105105+module_param(update_time2, int, UPDATE_TIME2);106106+107107+static int acpi_sbs_add(struct acpi_device *device);108108+static int acpi_sbs_remove(struct acpi_device *device, int type);109109+static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);110110+static void acpi_sbs_update_queue(void *data);111111+112112+static struct acpi_driver acpi_sbs_driver = {113113+ .name = ACPI_SBS_DRIVER_NAME,114114+ .class = ACPI_SBS_CLASS,115115+ .ids = ACPI_SBS_HID,116116+ .ops = {117117+ .add = acpi_sbs_add,118118+ .remove = acpi_sbs_remove,119119+ },120120+};121121+122122+struct acpi_battery_info {123123+ int capacity_mode;124124+ s16 full_charge_capacity;125125+ s16 design_capacity;126126+ s16 design_voltage;127127+ int vscale;128128+ int ipscale;129129+ s16 serial_number;130130+ char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];131131+ char device_name[I2C_SMBUS_BLOCK_MAX + 3];132132+ char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];133133+};134134+135135+struct acpi_battery_state {136136+ s16 voltage;137137+ s16 amperage;138138+ s16 remaining_capacity;139139+ s16 average_time_to_empty;140140+ s16 average_time_to_full;141141+ s16 battery_status;142142+};143143+144144+struct acpi_battery_alarm {145145+ s16 remaining_capacity;146146+};147147+148148+struct acpi_battery {149149+ int alive;150150+ int battery_present;151151+ int id;152152+ int init_state;153153+ struct acpi_sbs *sbs;154154+ struct acpi_battery_info info;155155+ struct acpi_battery_state state;156156+ struct acpi_battery_alarm alarm;157157+ struct proc_dir_entry *battery_entry;158158+};159159+160160+struct acpi_sbs {161161+ acpi_handle handle;162162+ struct acpi_device *device;163163+ struct acpi_ec_smbus *smbus;164164+ int sbsm_present;165165+ int sbsm_batteries_supported;166166+ int ac_present;167167+ struct proc_dir_entry *ac_entry;168168+ struct acpi_battery battery[MAX_SBS_BAT];169169+ int update_info_mode;170170+ int zombie;171171+ int update_time;172172+ int update_time2;173173+ struct timer_list update_timer;174174+};175175+176176+static void acpi_update_delay(struct acpi_sbs *sbs);177177+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);178178+179179+/* --------------------------------------------------------------------------180180+ SMBus Communication181181+ -------------------------------------------------------------------------- */182182+183183+static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)184184+{185185+ union i2c_smbus_data data;186186+ int result = 0;187187+ char *err_str;188188+ int err_number;189189+190190+ data.word = 0;191191+192192+ result = smbus->adapter.algo->193193+ smbus_xfer(&smbus->adapter,194194+ ACPI_SB_SMBUS_ADDR,195195+ 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);196196+197197+ err_number = (data.word & 0x000f);198198+199199+ switch (data.word & 0x000f) {200200+ case 0x0000:201201+ err_str = "unexpected bus error";202202+ break;203203+ case 0x0001:204204+ err_str = "busy";205205+ break;206206+ case 0x0002:207207+ err_str = "reserved command";208208+ break;209209+ case 0x0003:210210+ err_str = "unsupported command";211211+ break;212212+ case 0x0004:213213+ err_str = "access denied";214214+ break;215215+ case 0x0005:216216+ err_str = "overflow/underflow";217217+ break;218218+ case 0x0006:219219+ err_str = "bad size";220220+ break;221221+ case 0x0007:222222+ err_str = "unknown error";223223+ break;224224+ default:225225+ err_str = "unrecognized error";226226+ }227227+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,228228+ "%s: ret %i, err %i\n", err_str, result, err_number));229229+}230230+231231+static int232232+acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,233233+ u16 * word,234234+ void (*err_handler) (struct acpi_ec_smbus * smbus))235235+{236236+ union i2c_smbus_data data;237237+ int result = 0;238238+ int i;239239+240240+ if (err_handler == NULL) {241241+ err_handler = acpi_battery_smbus_err_handler;242242+ }243243+244244+ for (i = 0; i < MAX_SMBUS_ERR; i++) {245245+ result =246246+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,247247+ I2C_SMBUS_READ, func,248248+ I2C_SMBUS_WORD_DATA, &data);249249+ if (result) {250250+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,251251+ "try %i: smbus->adapter.algo->smbus_xfer() failed\n",252252+ i));253253+ if (err_handler) {254254+ err_handler(smbus);255255+ }256256+ } else {257257+ *word = data.word;258258+ break;259259+ }260260+ }261261+262262+ return result;263263+}264264+265265+static int266266+acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,267267+ char *str,268268+ void (*err_handler) (struct acpi_ec_smbus * smbus))269269+{270270+ union i2c_smbus_data data;271271+ int result = 0;272272+ int i;273273+274274+ if (err_handler == NULL) {275275+ err_handler = acpi_battery_smbus_err_handler;276276+ }277277+278278+ for (i = 0; i < MAX_SMBUS_ERR; i++) {279279+ result =280280+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,281281+ I2C_SMBUS_READ, func,282282+ I2C_SMBUS_BLOCK_DATA,283283+ &data);284284+ if (result) {285285+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,286286+ "try %i: smbus->adapter.algo->smbus_xfer() failed\n",287287+ i));288288+ if (err_handler) {289289+ err_handler(smbus);290290+ }291291+ } else {292292+ strncpy(str, (const char *)data.block + 1,293293+ data.block[0]);294294+ str[data.block[0]] = 0;295295+ break;296296+ }297297+ }298298+299299+ return result;300300+}301301+302302+static int303303+acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,304304+ int word,305305+ void (*err_handler) (struct acpi_ec_smbus * smbus))306306+{307307+ union i2c_smbus_data data;308308+ int result = 0;309309+ int i;310310+311311+ if (err_handler == NULL) {312312+ err_handler = acpi_battery_smbus_err_handler;313313+ }314314+315315+ data.word = word;316316+317317+ for (i = 0; i < MAX_SMBUS_ERR; i++) {318318+ result =319319+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,320320+ I2C_SMBUS_WRITE, func,321321+ I2C_SMBUS_WORD_DATA, &data);322322+ if (result) {323323+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,324324+ "try %i: smbus->adapter.algo"325325+ "->smbus_xfer() failed\n", i));326326+ if (err_handler) {327327+ err_handler(smbus);328328+ }329329+ } else {330330+ break;331331+ }332332+ }333333+334334+ return result;335335+}336336+337337+/* --------------------------------------------------------------------------338338+ Smart Battery System Management339339+ -------------------------------------------------------------------------- */340340+341341+/* Smart Battery */342342+343343+static int acpi_sbs_generate_event(struct acpi_device *device,344344+ int event, int state, char *bid, char *class)345345+{346346+ char bid_saved[5];347347+ char class_saved[20];348348+ int result = 0;349349+350350+ strcpy(bid_saved, acpi_device_bid(device));351351+ strcpy(class_saved, acpi_device_class(device));352352+353353+ strcpy(acpi_device_bid(device), bid);354354+ strcpy(acpi_device_class(device), class);355355+356356+ result = acpi_bus_generate_event(device, event, state);357357+358358+ strcpy(acpi_device_bid(device), bid_saved);359359+ strcpy(acpi_device_class(device), class_saved);360360+361361+ return result;362362+}363363+364364+static int acpi_battery_get_present(struct acpi_battery *battery)365365+{366366+ s16 state;367367+ int result = 0;368368+ int is_present = 0;369369+370370+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,371371+ ACPI_SBSM_SMBUS_ADDR, 0x01,372372+ &state, NULL);373373+ if (result) {374374+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,375375+ "acpi_sbs_smbus_read_word() failed"));376376+ }377377+ if (!result) {378378+ is_present = (state & 0x000f) & (1 << battery->id);379379+ }380380+ battery->battery_present = is_present;381381+382382+ return result;383383+}384384+385385+static int acpi_battery_is_present(struct acpi_battery *battery)386386+{387387+ return (battery->battery_present);388388+}389389+390390+static int acpi_ac_is_present(struct acpi_sbs *sbs)391391+{392392+ return (sbs->ac_present);393393+}394394+395395+static int acpi_battery_select(struct acpi_battery *battery)396396+{397397+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;398398+ int result = 0;399399+ s16 state;400400+ int foo;401401+402402+ if (battery->sbs->sbsm_present) {403403+404404+ /* Take special care not to knobble other nibbles of405405+ * state (aka selector_state), since406406+ * it causes charging to halt on SBSELs */407407+408408+ result =409409+ acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,410410+ &state, NULL);411411+ if (result) {412412+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,413413+ "acpi_sbs_smbus_read_word() failed\n"));414414+ goto end;415415+ }416416+417417+ foo = (state & 0x0fff) | (1 << (battery->id + 12));418418+ result =419419+ acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,420420+ foo, NULL);421421+ if (result) {422422+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,423423+ "acpi_sbs_smbus_write_word() failed\n"));424424+ goto end;425425+ }426426+ }427427+428428+ end:429429+ return result;430430+}431431+432432+static int acpi_sbsm_get_info(struct acpi_sbs *sbs)433433+{434434+ struct acpi_ec_smbus *smbus = sbs->smbus;435435+ int result = 0;436436+ s16 battery_system_info;437437+438438+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,439439+ &battery_system_info, NULL);440440+ if (result) {441441+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,442442+ "acpi_sbs_smbus_read_word() failed\n"));443443+ goto end;444444+ }445445+446446+ sbs->sbsm_batteries_supported = battery_system_info & 0x000f;447447+448448+ end:449449+450450+ return result;451451+}452452+453453+static int acpi_battery_get_info(struct acpi_battery *battery)454454+{455455+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;456456+ int result = 0;457457+ s16 battery_mode;458458+ s16 specification_info;459459+460460+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,461461+ &battery_mode,462462+ &acpi_battery_smbus_err_handler);463463+ if (result) {464464+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,465465+ "acpi_sbs_smbus_read_word() failed\n"));466466+ goto end;467467+ }468468+ battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;469469+470470+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,471471+ &battery->info.full_charge_capacity,472472+ &acpi_battery_smbus_err_handler);473473+ if (result) {474474+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,475475+ "acpi_sbs_smbus_read_word() failed\n"));476476+ goto end;477477+ }478478+479479+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,480480+ &battery->info.design_capacity,481481+ &acpi_battery_smbus_err_handler);482482+483483+ if (result) {484484+ goto end;485485+ }486486+487487+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,488488+ &battery->info.design_voltage,489489+ &acpi_battery_smbus_err_handler);490490+ if (result) {491491+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,492492+ "acpi_sbs_smbus_read_word() failed\n"));493493+ goto end;494494+ }495495+496496+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,497497+ &specification_info,498498+ &acpi_battery_smbus_err_handler);499499+ if (result) {500500+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,501501+ "acpi_sbs_smbus_read_word() failed\n"));502502+ goto end;503503+ }504504+505505+ switch ((specification_info & 0x0f00) >> 8) {506506+ case 1:507507+ battery->info.vscale = 10;508508+ break;509509+ case 2:510510+ battery->info.vscale = 100;511511+ break;512512+ case 3:513513+ battery->info.vscale = 1000;514514+ break;515515+ default:516516+ battery->info.vscale = 1;517517+ }518518+519519+ switch ((specification_info & 0xf000) >> 12) {520520+ case 1:521521+ battery->info.ipscale = 10;522522+ break;523523+ case 2:524524+ battery->info.ipscale = 100;525525+ break;526526+ case 3:527527+ battery->info.ipscale = 1000;528528+ break;529529+ default:530530+ battery->info.ipscale = 1;531531+ }532532+533533+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,534534+ &battery->info.serial_number,535535+ &acpi_battery_smbus_err_handler);536536+ if (result) {537537+ goto end;538538+ }539539+540540+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,541541+ battery->info.manufacturer_name,542542+ &acpi_battery_smbus_err_handler);543543+ if (result) {544544+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,545545+ "acpi_sbs_smbus_read_str() failed\n"));546546+ goto end;547547+ }548548+549549+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,550550+ battery->info.device_name,551551+ &acpi_battery_smbus_err_handler);552552+ if (result) {553553+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,554554+ "acpi_sbs_smbus_read_str() failed\n"));555555+ goto end;556556+ }557557+558558+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,559559+ battery->info.device_chemistry,560560+ &acpi_battery_smbus_err_handler);561561+ if (result) {562562+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,563563+ "acpi_sbs_smbus_read_str() failed\n"));564564+ goto end;565565+ }566566+567567+ end:568568+ return result;569569+}570570+571571+static void acpi_update_delay(struct acpi_sbs *sbs)572572+{573573+ if (sbs->zombie) {574574+ return;575575+ }576576+ if (sbs->update_time2 > 0) {577577+ msleep(sbs->update_time2 * 1000);578578+ }579579+}580580+581581+static int acpi_battery_get_state(struct acpi_battery *battery)582582+{583583+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;584584+ int result = 0;585585+586586+ acpi_update_delay(battery->sbs);587587+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,588588+ &battery->state.voltage,589589+ &acpi_battery_smbus_err_handler);590590+ if (result) {591591+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,592592+ "acpi_sbs_smbus_read_word() failed\n"));593593+ goto end;594594+ }595595+596596+ acpi_update_delay(battery->sbs);597597+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,598598+ &battery->state.amperage,599599+ &acpi_battery_smbus_err_handler);600600+ if (result) {601601+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,602602+ "acpi_sbs_smbus_read_word() failed\n"));603603+ goto end;604604+ }605605+606606+ acpi_update_delay(battery->sbs);607607+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,608608+ &battery->state.remaining_capacity,609609+ &acpi_battery_smbus_err_handler);610610+ if (result) {611611+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,612612+ "acpi_sbs_smbus_read_word() failed\n"));613613+ goto end;614614+ }615615+616616+ acpi_update_delay(battery->sbs);617617+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,618618+ &battery->state.average_time_to_empty,619619+ &acpi_battery_smbus_err_handler);620620+ if (result) {621621+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,622622+ "acpi_sbs_smbus_read_word() failed\n"));623623+ goto end;624624+ }625625+626626+ acpi_update_delay(battery->sbs);627627+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,628628+ &battery->state.average_time_to_full,629629+ &acpi_battery_smbus_err_handler);630630+ if (result) {631631+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,632632+ "acpi_sbs_smbus_read_word() failed\n"));633633+ goto end;634634+ }635635+636636+ acpi_update_delay(battery->sbs);637637+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,638638+ &battery->state.battery_status,639639+ &acpi_battery_smbus_err_handler);640640+ if (result) {641641+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,642642+ "acpi_sbs_smbus_read_word() failed\n"));643643+ goto end;644644+ }645645+646646+ acpi_update_delay(battery->sbs);647647+648648+ end:649649+ return result;650650+}651651+652652+static int acpi_battery_get_alarm(struct acpi_battery *battery)653653+{654654+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;655655+ int result = 0;656656+657657+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,658658+ &battery->alarm.remaining_capacity,659659+ &acpi_battery_smbus_err_handler);660660+ if (result) {661661+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,662662+ "acpi_sbs_smbus_read_word() failed\n"));663663+ goto end;664664+ }665665+666666+ acpi_update_delay(battery->sbs);667667+668668+ end:669669+670670+ return result;671671+}672672+673673+static int acpi_battery_set_alarm(struct acpi_battery *battery,674674+ unsigned long alarm)675675+{676676+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;677677+ int result = 0;678678+ s16 battery_mode;679679+ int foo;680680+681681+ result = acpi_battery_select(battery);682682+ if (result) {683683+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,684684+ "acpi_battery_select() failed\n"));685685+ goto end;686686+ }687687+688688+ /* If necessary, enable the alarm */689689+690690+ if (alarm > 0) {691691+ result =692692+ acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,693693+ &battery_mode,694694+ &acpi_battery_smbus_err_handler);695695+ if (result) {696696+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,697697+ "acpi_sbs_smbus_read_word() failed\n"));698698+ goto end;699699+ }700700+701701+ result =702702+ acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,703703+ battery_mode & 0xbfff,704704+ &acpi_battery_smbus_err_handler);705705+ if (result) {706706+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,707707+ "acpi_sbs_smbus_write_word() failed\n"));708708+ goto end;709709+ }710710+ }711711+712712+ foo = alarm / (battery->info.capacity_mode ? 10 : 1);713713+ result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,714714+ foo,715715+ &acpi_battery_smbus_err_handler);716716+ if (result) {717717+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,718718+ "acpi_sbs_smbus_write_word() failed\n"));719719+ goto end;720720+ }721721+722722+ end:723723+724724+ return result;725725+}726726+727727+static int acpi_battery_set_mode(struct acpi_battery *battery)728728+{729729+ int result = 0;730730+ s16 battery_mode;731731+732732+ if (capacity_mode == DEF_CAPACITY_UNIT) {733733+ goto end;734734+ }735735+736736+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,737737+ ACPI_SB_SMBUS_ADDR, 0x03,738738+ &battery_mode, NULL);739739+ if (result) {740740+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,741741+ "acpi_sbs_smbus_read_word() failed\n"));742742+ goto end;743743+ }744744+745745+ if (capacity_mode == MAH_CAPACITY_UNIT) {746746+ battery_mode &= 0x7fff;747747+ } else {748748+ battery_mode |= 0x8000;749749+ }750750+ result = acpi_sbs_smbus_write_word(battery->sbs->smbus,751751+ ACPI_SB_SMBUS_ADDR, 0x03,752752+ battery_mode, NULL);753753+ if (result) {754754+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,755755+ "acpi_sbs_smbus_write_word() failed\n"));756756+ goto end;757757+ }758758+759759+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,760760+ ACPI_SB_SMBUS_ADDR, 0x03,761761+ &battery_mode, NULL);762762+ if (result) {763763+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,764764+ "acpi_sbs_smbus_read_word() failed\n"));765765+ goto end;766766+ }767767+768768+ end:769769+ return result;770770+}771771+772772+static int acpi_battery_init(struct acpi_battery *battery)773773+{774774+ int result = 0;775775+776776+ result = acpi_battery_select(battery);777777+ if (result) {778778+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,779779+ "acpi_battery_init() failed\n"));780780+ goto end;781781+ }782782+783783+ result = acpi_battery_set_mode(battery);784784+ if (result) {785785+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,786786+ "acpi_battery_set_mode() failed\n"));787787+ goto end;788788+ }789789+790790+ result = acpi_battery_get_info(battery);791791+ if (result) {792792+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,793793+ "acpi_battery_get_info() failed\n"));794794+ goto end;795795+ }796796+797797+ result = acpi_battery_get_state(battery);798798+ if (result) {799799+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,800800+ "acpi_battery_get_state() failed\n"));801801+ goto end;802802+ }803803+804804+ result = acpi_battery_get_alarm(battery);805805+ if (result) {806806+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,807807+ "acpi_battery_get_alarm() failed\n"));808808+ goto end;809809+ }810810+811811+ end:812812+ return result;813813+}814814+815815+static int acpi_ac_get_present(struct acpi_sbs *sbs)816816+{817817+ struct acpi_ec_smbus *smbus = sbs->smbus;818818+ int result = 0;819819+ s16 charger_status;820820+821821+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,822822+ &charger_status, NULL);823823+824824+ if (result) {825825+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,826826+ "acpi_sbs_smbus_read_word() failed\n"));827827+ goto end;828828+ }829829+830830+ sbs->ac_present = (charger_status & 0x8000) >> 15;831831+832832+ end:833833+834834+ return result;835835+}836836+837837+/* --------------------------------------------------------------------------838838+ FS Interface (/proc/acpi)839839+ -------------------------------------------------------------------------- */840840+841841+/* Generic Routines */842842+843843+static int844844+acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,845845+ struct proc_dir_entry *parent_dir,846846+ char *dir_name,847847+ struct file_operations *info_fops,848848+ struct file_operations *state_fops,849849+ struct file_operations *alarm_fops, void *data)850850+{851851+ struct proc_dir_entry *entry = NULL;852852+853853+ if (!*dir) {854854+ *dir = proc_mkdir(dir_name, parent_dir);855855+ if (!*dir) {856856+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,857857+ "proc_mkdir() failed\n"));858858+ return -ENODEV;859859+ }860860+ (*dir)->owner = THIS_MODULE;861861+ }862862+863863+ /* 'info' [R] */864864+ if (info_fops) {865865+ entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);866866+ if (!entry) {867867+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,868868+ "create_proc_entry() failed\n"));869869+ } else {870870+ entry->proc_fops = info_fops;871871+ entry->data = data;872872+ entry->owner = THIS_MODULE;873873+ }874874+ }875875+876876+ /* 'state' [R] */877877+ if (state_fops) {878878+ entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);879879+ if (!entry) {880880+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,881881+ "create_proc_entry() failed\n"));882882+ } else {883883+ entry->proc_fops = state_fops;884884+ entry->data = data;885885+ entry->owner = THIS_MODULE;886886+ }887887+ }888888+889889+ /* 'alarm' [R/W] */890890+ if (alarm_fops) {891891+ entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);892892+ if (!entry) {893893+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,894894+ "create_proc_entry() failed\n"));895895+ } else {896896+ entry->proc_fops = alarm_fops;897897+ entry->data = data;898898+ entry->owner = THIS_MODULE;899899+ }900900+ }901901+902902+ return 0;903903+}904904+905905+static void906906+acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,907907+ struct proc_dir_entry *parent_dir)908908+{909909+910910+ if (*dir) {911911+ remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);912912+ remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);913913+ remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);914914+ remove_proc_entry((*dir)->name, parent_dir);915915+ *dir = NULL;916916+ }917917+918918+}919919+920920+/* Smart Battery Interface */921921+922922+static struct proc_dir_entry *acpi_battery_dir = NULL;923923+924924+static int acpi_battery_read_info(struct seq_file *seq, void *offset)925925+{926926+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;927927+ int cscale;928928+ int result = 0;929929+930930+ if (battery->sbs->zombie) {931931+ return -ENODEV;932932+ }933933+934934+ down(&sbs_sem);935935+936936+ if (update_mode == REQUEST_UPDATE_MODE) {937937+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);938938+ if (result) {939939+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,940940+ "acpi_sbs_update_run() failed\n"));941941+ }942942+ }943943+944944+ if (acpi_battery_is_present(battery)) {945945+ seq_printf(seq, "present: yes\n");946946+ } else {947947+ seq_printf(seq, "present: no\n");948948+ goto end;949949+ }950950+951951+ if (battery->info.capacity_mode) {952952+ cscale = battery->info.vscale * battery->info.ipscale;953953+ } else {954954+ cscale = battery->info.ipscale;955955+ }956956+ seq_printf(seq, "design capacity: %i%s",957957+ battery->info.design_capacity * cscale,958958+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");959959+960960+ seq_printf(seq, "last full capacity: %i%s",961961+ battery->info.full_charge_capacity * cscale,962962+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");963963+964964+ seq_printf(seq, "battery technology: rechargeable\n");965965+966966+ seq_printf(seq, "design voltage: %i mV\n",967967+ battery->info.design_voltage * battery->info.vscale);968968+969969+ seq_printf(seq, "design capacity warning: unknown\n");970970+ seq_printf(seq, "design capacity low: unknown\n");971971+ seq_printf(seq, "capacity granularity 1: unknown\n");972972+ seq_printf(seq, "capacity granularity 2: unknown\n");973973+974974+ seq_printf(seq, "model number: %s\n",975975+ battery->info.device_name);976976+977977+ seq_printf(seq, "serial number: %i\n",978978+ battery->info.serial_number);979979+980980+ seq_printf(seq, "battery type: %s\n",981981+ battery->info.device_chemistry);982982+983983+ seq_printf(seq, "OEM info: %s\n",984984+ battery->info.manufacturer_name);985985+986986+ end:987987+988988+ up(&sbs_sem);989989+990990+ return result;991991+}992992+993993+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)994994+{995995+ return single_open(file, acpi_battery_read_info, PDE(inode)->data);996996+}997997+998998+static int acpi_battery_read_state(struct seq_file *seq, void *offset)999999+{10001000+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;10011001+ int result = 0;10021002+ int cscale;10031003+ int foo;10041004+10051005+ if (battery->sbs->zombie) {10061006+ return -ENODEV;10071007+ }10081008+10091009+ down(&sbs_sem);10101010+10111011+ if (update_mode == REQUEST_UPDATE_MODE) {10121012+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);10131013+ if (result) {10141014+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,10151015+ "acpi_sbs_update_run() failed\n"));10161016+ }10171017+ }10181018+10191019+ if (acpi_battery_is_present(battery)) {10201020+ seq_printf(seq, "present: yes\n");10211021+ } else {10221022+ seq_printf(seq, "present: no\n");10231023+ goto end;10241024+ }10251025+10261026+ if (battery->info.capacity_mode) {10271027+ cscale = battery->info.vscale * battery->info.ipscale;10281028+ } else {10291029+ cscale = battery->info.ipscale;10301030+ }10311031+10321032+ if (battery->state.battery_status & 0x0010) {10331033+ seq_printf(seq, "capacity state: critical\n");10341034+ } else {10351035+ seq_printf(seq, "capacity state: ok\n");10361036+ }10371037+ if (battery->state.amperage < 0) {10381038+ seq_printf(seq, "charging state: discharging\n");10391039+ foo = battery->state.remaining_capacity * cscale * 60 /10401040+ (battery->state.average_time_to_empty == 0 ? 1 :10411041+ battery->state.average_time_to_empty);10421042+ seq_printf(seq, "present rate: %i%s\n",10431043+ foo, battery->info.capacity_mode ? "0 mW" : " mA");10441044+ } else if (battery->state.amperage > 0) {10451045+ seq_printf(seq, "charging state: charging\n");10461046+ foo = (battery->info.full_charge_capacity -10471047+ battery->state.remaining_capacity) * cscale * 60 /10481048+ (battery->state.average_time_to_full == 0 ? 1 :10491049+ battery->state.average_time_to_full);10501050+ seq_printf(seq, "present rate: %i%s\n",10511051+ foo, battery->info.capacity_mode ? "0 mW" : " mA");10521052+ } else {10531053+ seq_printf(seq, "charging state: charged\n");10541054+ seq_printf(seq, "present rate: 0 %s\n",10551055+ battery->info.capacity_mode ? "mW" : "mA");10561056+ }10571057+10581058+ seq_printf(seq, "remaining capacity: %i%s",10591059+ battery->state.remaining_capacity * cscale,10601060+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");10611061+10621062+ seq_printf(seq, "present voltage: %i mV\n",10631063+ battery->state.voltage * battery->info.vscale);10641064+10651065+ end:10661066+10671067+ up(&sbs_sem);10681068+10691069+ return result;10701070+}10711071+10721072+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)10731073+{10741074+ return single_open(file, acpi_battery_read_state, PDE(inode)->data);10751075+}10761076+10771077+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)10781078+{10791079+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;10801080+ int result = 0;10811081+ int cscale;10821082+10831083+ if (battery->sbs->zombie) {10841084+ return -ENODEV;10851085+ }10861086+10871087+ down(&sbs_sem);10881088+10891089+ if (update_mode == REQUEST_UPDATE_MODE) {10901090+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);10911091+ if (result) {10921092+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,10931093+ "acpi_sbs_update_run() failed\n"));10941094+ }10951095+ }10961096+10971097+ if (!acpi_battery_is_present(battery)) {10981098+ seq_printf(seq, "present: no\n");10991099+ goto end;11001100+ }11011101+11021102+ if (battery->info.capacity_mode) {11031103+ cscale = battery->info.vscale * battery->info.ipscale;11041104+ } else {11051105+ cscale = battery->info.ipscale;11061106+ }11071107+11081108+ seq_printf(seq, "alarm: ");11091109+ if (battery->alarm.remaining_capacity) {11101110+ seq_printf(seq, "%i%s",11111111+ battery->alarm.remaining_capacity * cscale,11121112+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");11131113+ } else {11141114+ seq_printf(seq, "disabled\n");11151115+ }11161116+11171117+ end:11181118+11191119+ up(&sbs_sem);11201120+11211121+ return result;11221122+}11231123+11241124+static ssize_t11251125+acpi_battery_write_alarm(struct file *file, const char __user * buffer,11261126+ size_t count, loff_t * ppos)11271127+{11281128+ struct seq_file *seq = (struct seq_file *)file->private_data;11291129+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;11301130+ char alarm_string[12] = { '\0' };11311131+ int result, old_alarm, new_alarm;11321132+11331133+ if (battery->sbs->zombie) {11341134+ return -ENODEV;11351135+ }11361136+11371137+ down(&sbs_sem);11381138+11391139+ if (!acpi_battery_is_present(battery)) {11401140+ result = -ENODEV;11411141+ goto end;11421142+ }11431143+11441144+ if (count > sizeof(alarm_string) - 1) {11451145+ result = -EINVAL;11461146+ goto end;11471147+ }11481148+11491149+ if (copy_from_user(alarm_string, buffer, count)) {11501150+ result = -EFAULT;11511151+ goto end;11521152+ }11531153+11541154+ alarm_string[count] = 0;11551155+11561156+ old_alarm = battery->alarm.remaining_capacity;11571157+ new_alarm = simple_strtoul(alarm_string, NULL, 0);11581158+11591159+ result = acpi_battery_set_alarm(battery, new_alarm);11601160+ if (result) {11611161+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,11621162+ "acpi_battery_set_alarm() failed\n"));11631163+ (void)acpi_battery_set_alarm(battery, old_alarm);11641164+ goto end;11651165+ }11661166+ result = acpi_battery_get_alarm(battery);11671167+ if (result) {11681168+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,11691169+ "acpi_battery_get_alarm() failed\n"));11701170+ (void)acpi_battery_set_alarm(battery, old_alarm);11711171+ goto end;11721172+ }11731173+11741174+ end:11751175+ up(&sbs_sem);11761176+11771177+ if (result) {11781178+ return result;11791179+ } else {11801180+ return count;11811181+ }11821182+}11831183+11841184+static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)11851185+{11861186+ return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);11871187+}11881188+11891189+static struct file_operations acpi_battery_info_fops = {11901190+ .open = acpi_battery_info_open_fs,11911191+ .read = seq_read,11921192+ .llseek = seq_lseek,11931193+ .release = single_release,11941194+ .owner = THIS_MODULE,11951195+};11961196+11971197+static struct file_operations acpi_battery_state_fops = {11981198+ .open = acpi_battery_state_open_fs,11991199+ .read = seq_read,12001200+ .llseek = seq_lseek,12011201+ .release = single_release,12021202+ .owner = THIS_MODULE,12031203+};12041204+12051205+static struct file_operations acpi_battery_alarm_fops = {12061206+ .open = acpi_battery_alarm_open_fs,12071207+ .read = seq_read,12081208+ .write = acpi_battery_write_alarm,12091209+ .llseek = seq_lseek,12101210+ .release = single_release,12111211+ .owner = THIS_MODULE,12121212+};12131213+12141214+/* Legacy AC Adapter Interface */12151215+12161216+static struct proc_dir_entry *acpi_ac_dir = NULL;12171217+12181218+static int acpi_ac_read_state(struct seq_file *seq, void *offset)12191219+{12201220+ struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private;12211221+ int result;12221222+12231223+ if (sbs->zombie) {12241224+ return -ENODEV;12251225+ }12261226+12271227+ down(&sbs_sem);12281228+12291229+ if (update_mode == REQUEST_UPDATE_MODE) {12301230+ result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);12311231+ if (result) {12321232+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,12331233+ "acpi_sbs_update_run() failed\n"));12341234+ }12351235+ }12361236+12371237+ seq_printf(seq, "state: %s\n",12381238+ sbs->ac_present ? "on-line" : "off-line");12391239+12401240+ up(&sbs_sem);12411241+12421242+ return 0;12431243+}12441244+12451245+static int acpi_ac_state_open_fs(struct inode *inode, struct file *file)12461246+{12471247+ return single_open(file, acpi_ac_read_state, PDE(inode)->data);12481248+}12491249+12501250+static struct file_operations acpi_ac_state_fops = {12511251+ .open = acpi_ac_state_open_fs,12521252+ .read = seq_read,12531253+ .llseek = seq_lseek,12541254+ .release = single_release,12551255+ .owner = THIS_MODULE,12561256+};12571257+12581258+/* --------------------------------------------------------------------------12591259+ Driver Interface12601260+ -------------------------------------------------------------------------- */12611261+12621262+/* Smart Battery */12631263+12641264+static int acpi_battery_add(struct acpi_sbs *sbs, int id)12651265+{12661266+ int is_present;12671267+ int result;12681268+ char dir_name[32];12691269+ struct acpi_battery *battery;12701270+12711271+ battery = &sbs->battery[id];12721272+12731273+ battery->alive = 0;12741274+12751275+ battery->init_state = 0;12761276+ battery->id = id;12771277+ battery->sbs = sbs;12781278+12791279+ result = acpi_battery_select(battery);12801280+ if (result) {12811281+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,12821282+ "acpi_battery_select() failed\n"));12831283+ goto end;12841284+ }12851285+12861286+ result = acpi_battery_get_present(battery);12871287+ if (result) {12881288+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,12891289+ "acpi_battery_get_present() failed\n"));12901290+ goto end;12911291+ }12921292+12931293+ is_present = acpi_battery_is_present(battery);12941294+12951295+ if (is_present) {12961296+ result = acpi_battery_init(battery);12971297+ if (result) {12981298+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,12991299+ "acpi_battery_init() failed\n"));13001300+ goto end;13011301+ }13021302+ battery->init_state = 1;13031303+ }13041304+13051305+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);13061306+13071307+ result = acpi_sbs_generic_add_fs(&battery->battery_entry,13081308+ acpi_battery_dir,13091309+ dir_name,13101310+ &acpi_battery_info_fops,13111311+ &acpi_battery_state_fops,13121312+ &acpi_battery_alarm_fops, battery);13131313+ if (result) {13141314+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,13151315+ "acpi_sbs_generic_add_fs() failed\n"));13161316+ goto end;13171317+ }13181318+ battery->alive = 1;13191319+13201320+ end:13211321+ return result;13221322+}13231323+13241324+static void acpi_battery_remove(struct acpi_sbs *sbs, int id)13251325+{13261326+13271327+ if (sbs->battery[id].battery_entry) {13281328+ acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry),13291329+ acpi_battery_dir);13301330+ }13311331+}13321332+13331333+static int acpi_ac_add(struct acpi_sbs *sbs)13341334+{13351335+ int result;13361336+13371337+ result = acpi_ac_get_present(sbs);13381338+ if (result) {13391339+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,13401340+ "acpi_ac_get_present() failed\n"));13411341+ goto end;13421342+ }13431343+13441344+ result = acpi_sbs_generic_add_fs(&sbs->ac_entry,13451345+ acpi_ac_dir,13461346+ ACPI_AC_DIR_NAME,13471347+ NULL, &acpi_ac_state_fops, NULL, sbs);13481348+ if (result) {13491349+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,13501350+ "acpi_sbs_generic_add_fs() failed\n"));13511351+ goto end;13521352+ }13531353+13541354+ end:13551355+13561356+ return result;13571357+}13581358+13591359+static void acpi_ac_remove(struct acpi_sbs *sbs)13601360+{13611361+13621362+ if (sbs->ac_entry) {13631363+ acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir);13641364+ }13651365+}13661366+13671367+static void acpi_sbs_update_queue_run(unsigned long data)13681368+{13691369+ acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);13701370+}13711371+13721372+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)13731373+{13741374+ struct acpi_battery *battery;13751375+ int result = 0;13761376+ int old_ac_present;13771377+ int old_battery_present;13781378+ int new_ac_present;13791379+ int new_battery_present;13801380+ int id;13811381+ char dir_name[32];13821382+ int do_battery_init, do_ac_init;13831383+ s16 old_remaining_capacity;13841384+13851385+ if (sbs->zombie) {13861386+ goto end;13871387+ }13881388+13891389+ old_ac_present = acpi_ac_is_present(sbs);13901390+13911391+ result = acpi_ac_get_present(sbs);13921392+ if (result) {13931393+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,13941394+ "acpi_ac_get_present() failed\n"));13951395+ }13961396+13971397+ new_ac_present = acpi_ac_is_present(sbs);13981398+13991399+ do_ac_init = (old_ac_present != new_ac_present);14001400+14011401+ if (data_type == DATA_TYPE_AC_STATE) {14021402+ goto end;14031403+ }14041404+14051405+ for (id = 0; id < MAX_SBS_BAT; id++) {14061406+ battery = &sbs->battery[id];14071407+ if (battery->alive == 0) {14081408+ continue;14091409+ }14101410+14111411+ old_remaining_capacity = battery->state.remaining_capacity;14121412+14131413+ old_battery_present = acpi_battery_is_present(battery);14141414+14151415+ result = acpi_battery_select(battery);14161416+ if (result) {14171417+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14181418+ "acpi_battery_select() failed\n"));14191419+ }14201420+ if (sbs->zombie) {14211421+ goto end;14221422+ }14231423+14241424+ result = acpi_battery_get_present(battery);14251425+ if (result) {14261426+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14271427+ "acpi_battery_get_present() failed\n"));14281428+ }14291429+ if (sbs->zombie) {14301430+ goto end;14311431+ }14321432+14331433+ new_battery_present = acpi_battery_is_present(battery);14341434+14351435+ do_battery_init = ((old_battery_present != new_battery_present)14361436+ && new_battery_present);14371437+14381438+ if (sbs->zombie) {14391439+ goto end;14401440+ }14411441+ if (do_ac_init || do_battery_init ||14421442+ update_info_mode || sbs->update_info_mode) {14431443+ if (sbs->update_info_mode) {14441444+ sbs->update_info_mode = 0;14451445+ } else {14461446+ sbs->update_info_mode = 1;14471447+ }14481448+ result = acpi_battery_init(battery);14491449+ if (result) {14501450+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14511451+ "acpi_battery_init() "14521452+ "failed\n"));14531453+ }14541454+ }14551455+ if (data_type == DATA_TYPE_INFO) {14561456+ continue;14571457+ }14581458+14591459+ if (sbs->zombie) {14601460+ goto end;14611461+ }14621462+ if (new_battery_present) {14631463+ result = acpi_battery_get_alarm(battery);14641464+ if (result) {14651465+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14661466+ "acpi_battery_get_alarm() "14671467+ "failed\n"));14681468+ }14691469+ if (data_type == DATA_TYPE_ALARM) {14701470+ continue;14711471+ }14721472+14731473+ result = acpi_battery_get_state(battery);14741474+ if (result) {14751475+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14761476+ "acpi_battery_get_state() "14771477+ "failed\n"));14781478+ }14791479+ }14801480+ if (sbs->zombie) {14811481+ goto end;14821482+ }14831483+ if (data_type != DATA_TYPE_COMMON) {14841484+ continue;14851485+ }14861486+14871487+ if (old_battery_present != new_battery_present) {14881488+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);14891489+ result = acpi_sbs_generate_event(sbs->device,14901490+ ACPI_SBS_BATTERY_NOTIFY_STATUS,14911491+ new_battery_present,14921492+ dir_name,14931493+ ACPI_BATTERY_CLASS);14941494+ if (result) {14951495+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,14961496+ "acpi_sbs_generate_event() "14971497+ "failed\n"));14981498+ }14991499+ }15001500+ if (old_remaining_capacity != battery->state.remaining_capacity) {15011501+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);15021502+ result = acpi_sbs_generate_event(sbs->device,15031503+ ACPI_SBS_BATTERY_NOTIFY_STATUS,15041504+ new_battery_present,15051505+ dir_name,15061506+ ACPI_BATTERY_CLASS);15071507+ if (result) {15081508+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,15091509+ "acpi_sbs_generate_event() failed\n"));15101510+ }15111511+ }15121512+15131513+ }15141514+ if (sbs->zombie) {15151515+ goto end;15161516+ }15171517+ if (data_type != DATA_TYPE_COMMON) {15181518+ goto end;15191519+ }15201520+15211521+ if (old_ac_present != new_ac_present) {15221522+ result = acpi_sbs_generate_event(sbs->device,15231523+ ACPI_SBS_AC_NOTIFY_STATUS,15241524+ new_ac_present,15251525+ ACPI_AC_DIR_NAME,15261526+ ACPI_AC_CLASS);15271527+ if (result) {15281528+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,15291529+ "acpi_sbs_generate_event() failed\n"));15301530+ }15311531+ }15321532+15331533+ end:15341534+ return result;15351535+}15361536+15371537+static void acpi_sbs_update_queue(void *data)15381538+{15391539+ struct acpi_sbs *sbs = data;15401540+ unsigned long delay = -1;15411541+ int result;15421542+15431543+ if (sbs->zombie) {15441544+ goto end;15451545+ }15461546+15471547+ result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);15481548+ if (result) {15491549+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,15501550+ "acpi_sbs_update_run() failed\n"));15511551+ }15521552+15531553+ if (sbs->zombie) {15541554+ goto end;15551555+ }15561556+15571557+ if (update_mode == REQUEST_UPDATE_MODE) {15581558+ goto end;15591559+ }15601560+15611561+ delay = jiffies + HZ * update_time;15621562+ sbs->update_timer.data = (unsigned long)data;15631563+ sbs->update_timer.function = acpi_sbs_update_queue_run;15641564+ sbs->update_timer.expires = delay;15651565+ add_timer(&sbs->update_timer);15661566+ end:15671567+ ;15681568+}15691569+15701570+static int acpi_sbs_add(struct acpi_device *device)15711571+{15721572+ struct acpi_sbs *sbs = NULL;15731573+ struct acpi_ec_hc *ec_hc = NULL;15741574+ int result, remove_result = 0;15751575+ unsigned long sbs_obj;15761576+ int id, cnt;15771577+ acpi_status status = AE_OK;15781578+15791579+ sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);15801580+ if (!sbs) {15811581+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));15821582+ return -ENOMEM;15831583+ }15841584+ memset(sbs, 0, sizeof(struct acpi_sbs));15851585+15861586+ cnt = 0;15871587+ while (cnt < 10) {15881588+ cnt++;15891589+ ec_hc = acpi_get_ec_hc(device);15901590+ if (ec_hc) {15911591+ break;15921592+ }15931593+ msleep(1000);15941594+ }15951595+15961596+ if (!ec_hc) {15971597+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,15981598+ "acpi_get_ec_hc() failed: "15991599+ "NO driver found for EC HC SMBus\n"));16001600+ result = -ENODEV;16011601+ goto end;16021602+ }16031603+16041604+ sbs->device = device;16051605+ sbs->smbus = ec_hc->smbus;16061606+16071607+ strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);16081608+ strcpy(acpi_device_class(device), ACPI_SBS_CLASS);16091609+ acpi_driver_data(device) = sbs;16101610+16111611+ sbs->update_time = 0;16121612+ sbs->update_time2 = 0;16131613+16141614+ result = acpi_ac_add(sbs);16151615+ if (result) {16161616+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));16171617+ goto end;16181618+ }16191619+ result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);16201620+ if (ACPI_FAILURE(result)) {16211621+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16221622+ "acpi_evaluate_integer() failed\n"));16231623+ result = -EIO;16241624+ goto end;16251625+ }16261626+16271627+ if (sbs_obj > 0) {16281628+ result = acpi_sbsm_get_info(sbs);16291629+ if (result) {16301630+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16311631+ "acpi_sbsm_get_info() failed\n"));16321632+ goto end;16331633+ }16341634+ sbs->sbsm_present = 1;16351635+ }16361636+ if (sbs->sbsm_present == 0) {16371637+ result = acpi_battery_add(sbs, 0);16381638+ if (result) {16391639+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16401640+ "acpi_battery_add() failed\n"));16411641+ goto end;16421642+ }16431643+ } else {16441644+ for (id = 0; id < MAX_SBS_BAT; id++) {16451645+ if ((sbs->sbsm_batteries_supported & (1 << id))) {16461646+ result = acpi_battery_add(sbs, id);16471647+ if (result) {16481648+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16491649+ "acpi_battery_add() "16501650+ "failed\n"));16511651+ goto end;16521652+ }16531653+ }16541654+ }16551655+ }16561656+16571657+ sbs->handle = device->handle;16581658+16591659+ init_timer(&sbs->update_timer);16601660+ if (update_mode == QUEUE_UPDATE_MODE) {16611661+ status = acpi_os_execute(OSL_GPE_HANDLER,16621662+ acpi_sbs_update_queue, (void *)sbs);16631663+ if (status != AE_OK) {16641664+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16651665+ "acpi_os_execute() failed\n"));16661666+ }16671667+ }16681668+ sbs->update_time = update_time;16691669+ sbs->update_time2 = update_time2;16701670+16711671+ printk(KERN_INFO PREFIX "%s [%s]\n",16721672+ acpi_device_name(device), acpi_device_bid(device));16731673+16741674+ end:16751675+ if (result) {16761676+ remove_result = acpi_sbs_remove(device, 0);16771677+ if (remove_result) {16781678+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,16791679+ "acpi_sbs_remove() failed\n"));16801680+ }16811681+ }16821682+16831683+ return result;16841684+}16851685+16861686+int acpi_sbs_remove(struct acpi_device *device, int type)16871687+{16881688+ struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);16891689+ int id;16901690+16911691+ if (!device || !sbs) {16921692+ return -EINVAL;16931693+ }16941694+16951695+ sbs->zombie = 1;16961696+ sbs->update_time = 0;16971697+ sbs->update_time2 = 0;16981698+ del_timer_sync(&sbs->update_timer);16991699+ acpi_os_wait_events_complete(NULL);17001700+ del_timer_sync(&sbs->update_timer);17011701+17021702+ for (id = 0; id < MAX_SBS_BAT; id++) {17031703+ acpi_battery_remove(sbs, id);17041704+ }17051705+17061706+ acpi_ac_remove(sbs);17071707+17081708+ kfree(sbs);17091709+17101710+ return 0;17111711+}17121712+17131713+static int __init acpi_sbs_init(void)17141714+{17151715+ int result = 0;17161716+17171717+ init_MUTEX(&sbs_sem);17181718+17191719+ if (capacity_mode != DEF_CAPACITY_UNIT17201720+ && capacity_mode != MAH_CAPACITY_UNIT17211721+ && capacity_mode != MWH_CAPACITY_UNIT) {17221722+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "17231723+ "invalid capacity_mode = %d\n",17241724+ capacity_mode));17251725+ return -EINVAL;17261726+ }17271727+17281728+ acpi_ac_dir = acpi_lock_ac_dir();17291729+ if (!acpi_ac_dir) {17301730+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,17311731+ "acpi_lock_ac_dir() failed\n"));17321732+ return -ENODEV;17331733+ }17341734+17351735+ acpi_battery_dir = acpi_lock_battery_dir();17361736+ if (!acpi_battery_dir) {17371737+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,17381738+ "acpi_lock_battery_dir() failed\n"));17391739+ return -ENODEV;17401740+ }17411741+17421742+ result = acpi_bus_register_driver(&acpi_sbs_driver);17431743+ if (result < 0) {17441744+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,17451745+ "acpi_bus_register_driver() failed\n"));17461746+ return -ENODEV;17471747+ }17481748+17491749+ return 0;17501750+}17511751+17521752+static void __exit acpi_sbs_exit(void)17531753+{17541754+17551755+ acpi_bus_unregister_driver(&acpi_sbs_driver);17561756+17571757+ acpi_unlock_ac_dir(acpi_ac_dir);17581758+ acpi_ac_dir = NULL;17591759+ acpi_unlock_battery_dir(acpi_battery_dir);17601760+ acpi_battery_dir = NULL;17611761+17621762+ return;17631763+}17641764+17651765+module_init(acpi_sbs_init);17661766+module_exit(acpi_sbs_exit);