Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
e270051d
Commit
e270051d
authored
Oct 10, 2007
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Pull battery-sbs-ac into release branch
parents
a2883dfa
d5b4a3d0
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1366 additions
and
1951 deletions
+1366
-1951
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+6
-7
drivers/acpi/Makefile
drivers/acpi/Makefile
+1
-0
drivers/acpi/ac.c
drivers/acpi/ac.c
+31
-2
drivers/acpi/battery.c
drivers/acpi/battery.c
+436
-602
drivers/acpi/bus.c
drivers/acpi/bus.c
+15
-8
drivers/acpi/ec.c
drivers/acpi/ec.c
+1
-2
drivers/acpi/sbs.c
drivers/acpi/sbs.c
+539
-1330
drivers/acpi/sbshc.c
drivers/acpi/sbshc.c
+309
-0
drivers/acpi/sbshc.h
drivers/acpi/sbshc.h
+27
-0
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+1
-0
No files found.
drivers/acpi/Kconfig
View file @
e270051d
...
...
@@ -88,7 +88,7 @@ config ACPI_PROC_EVENT
config ACPI_AC
tristate "AC Adapter"
depends on X86
depends on X86
&& POWER_SUPPLY
default y
help
This driver adds support for the AC Adapter object, which indicates
...
...
@@ -97,7 +97,7 @@ config ACPI_AC
config ACPI_BATTERY
tristate "Battery"
depends on X86
depends on X86
&& POWER_SUPPLY
default y
help
This driver adds support for battery information through
...
...
@@ -350,12 +350,11 @@ config ACPI_HOTPLUG_MEMORY
$>modprobe acpi_memhotplug
config ACPI_SBS
tristate "Smart Battery System
(EXPERIMENTAL)
"
tristate "Smart Battery System"
depends on X86
depends on
EXPERIMENTAL
depends on
POWER_SUPPLY
help
This driver adds support for the Smart Battery System.
A "Smart Battery" is quite old and quite rare compared
to today's ACPI "Control Method" battery.
This driver adds support for the Smart Battery System, another
type of access to battery information, found on some laptops.
endif # ACPI
drivers/acpi/Makefile
View file @
e270051d
...
...
@@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)
+=
acpi_memhotplug.o
obj-y
+=
cm_sbs.o
obj-$(CONFIG_ACPI_SBS)
+=
sbs.o
obj-$(CONFIG_ACPI_SBS)
+=
sbshc.o
drivers/acpi/ac.c
View file @
e270051d
...
...
@@ -29,6 +29,7 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/power_supply.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
...
...
@@ -72,16 +73,37 @@ static struct acpi_driver acpi_ac_driver = {
};
struct
acpi_ac
{
struct
power_supply
charger
;
struct
acpi_device
*
device
;
unsigned
long
state
;
};
#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
static
const
struct
file_operations
acpi_ac_fops
=
{
.
open
=
acpi_ac_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
get_ac_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
{
struct
acpi_ac
*
ac
=
to_acpi_ac
(
psy
);
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_ONLINE
:
val
->
intval
=
ac
->
state
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
static
enum
power_supply_property
ac_props
[]
=
{
POWER_SUPPLY_PROP_ONLINE
,
};
/* --------------------------------------------------------------------------
AC Adapter Management
...
...
@@ -208,6 +230,7 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
acpi_bus_generate_netlink_event
(
device
->
pnp
.
device_class
,
device
->
dev
.
bus_id
,
event
,
(
u32
)
ac
->
state
);
kobject_uevent
(
&
ac
->
charger
.
dev
->
kobj
,
KOBJ_CHANGE
);
break
;
default:
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
...
...
@@ -244,7 +267,12 @@ static int acpi_ac_add(struct acpi_device *device)
result
=
acpi_ac_add_fs
(
device
);
if
(
result
)
goto
end
;
ac
->
charger
.
name
=
acpi_device_bid
(
device
);
ac
->
charger
.
type
=
POWER_SUPPLY_TYPE_MAINS
;
ac
->
charger
.
properties
=
ac_props
;
ac
->
charger
.
num_properties
=
ARRAY_SIZE
(
ac_props
);
ac
->
charger
.
get_property
=
get_ac_property
;
power_supply_register
(
&
ac
->
device
->
dev
,
&
ac
->
charger
);
status
=
acpi_install_notify_handler
(
device
->
handle
,
ACPI_ALL_NOTIFY
,
acpi_ac_notify
,
ac
);
...
...
@@ -279,7 +307,8 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
status
=
acpi_remove_notify_handler
(
device
->
handle
,
ACPI_ALL_NOTIFY
,
acpi_ac_notify
);
if
(
ac
->
charger
.
dev
)
power_supply_unregister
(
&
ac
->
charger
);
acpi_ac_remove_fs
(
device
);
kfree
(
ac
);
...
...
drivers/acpi/battery.c
View file @
e270051d
/*
*
acpi_battery.c - ACPI Battery Driver ($Revision: 37 $
)
*
battery.c - ACPI Battery Driver (Revision: 2.0
)
*
* Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
* Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
...
...
@@ -27,244 +29,288 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/jiffies.h>
#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#
define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
#
include <linux/power_supply.h>
#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
#define ACPI_BATTERY_FORMAT_BST "NNNN"
#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
#define ACPI_BATTERY_COMPONENT 0x00040000
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_BATTERY_NOTIFY_INFO 0x81
#define ACPI_BATTERY_UNITS_WATTS "mW"
#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
#define ACPI_BATTERY_UPDATE_TIME 0
#define ACPI_BATTERY_NONE_UPDATE 0
#define ACPI_BATTERY_EASY_UPDATE 1
#define ACPI_BATTERY_INIT_UPDATE 2
ACPI_MODULE_NAME
(
"battery"
);
MODULE_AUTHOR
(
"Paul Diefenbaugh"
);
MODULE_AUTHOR
(
"Alexey Starikovskiy <astarikovskiy@suse.de>"
);
MODULE_DESCRIPTION
(
"ACPI Battery Driver"
);
MODULE_LICENSE
(
"GPL"
);
static
unsigned
int
update_time
=
ACPI_BATTERY_UPDATE_TIME
;
/* 0 - every time, > 0 - by update_time */
module_param
(
update_time
,
uint
,
0644
);
static
unsigned
int
cache_time
=
1000
;
module_param
(
cache_time
,
uint
,
0644
);
MODULE_PARM_DESC
(
cache_time
,
"cache time in milliseconds"
);
#ifdef CONFIG_ACPI_PROCFS
extern
struct
proc_dir_entry
*
acpi_lock_battery_dir
(
void
);
extern
void
*
acpi_unlock_battery_dir
(
struct
proc_dir_entry
*
acpi_battery_dir
);
static
int
acpi_battery_add
(
struct
acpi_device
*
device
);
static
int
acpi_battery_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_battery_resume
(
struct
acpi_device
*
device
);
enum
acpi_battery_files
{
info_tag
=
0
,
state_tag
,
alarm_tag
,
ACPI_BATTERY_NUMFILES
,
};
#endif
static
const
struct
acpi_device_id
battery_device_ids
[]
=
{
{
"PNP0C0A"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
battery_device_ids
);
static
struct
acpi_driver
acpi_battery_driver
=
{
.
name
=
"battery"
,
.
class
=
ACPI_BATTERY_CLASS
,
.
ids
=
battery_device_ids
,
.
ops
=
{
.
add
=
acpi_battery_add
,
.
resume
=
acpi_battery_resume
,
.
remove
=
acpi_battery_remove
,
},
};
struct
acpi_battery_state
{
acpi_integer
state
;
acpi_integer
present_rate
;
acpi_integer
remaining_capacity
;
acpi_integer
present_voltage
;
};
struct
acpi_battery_info
{
acpi_integer
power_unit
;
acpi_integer
design_capacity
;
acpi_integer
last_full_capacity
;
acpi_integer
battery_technology
;
acpi_integer
design_voltage
;
acpi_integer
design_capacity_warning
;
acpi_integer
design_capacity_low
;
acpi_integer
battery_capacity_granularity_1
;
acpi_integer
battery_capacity_granularity_2
;
acpi_string
model_number
;
acpi_string
serial_number
;
acpi_string
battery_type
;
acpi_string
oem_info
;
};
MODULE_DEVICE_TABLE
(
acpi
,
battery_device_ids
);
enum
acpi_battery_files
{
ACPI_BATTERY_INFO
=
0
,
ACPI_BATTERY_STATE
,
ACPI_BATTERY_ALARM
,
ACPI_BATTERY_NUMFILES
,
};
struct
acpi_battery_flags
{
u8
battery_present_prev
;
u8
alarm_present
;
u8
init_update
;
u8
update
[
ACPI_BATTERY_NUMFILES
];
u8
power_unit
;
};
struct
acpi_battery
{
struct
mutex
mutex
;
struct
mutex
lock
;
struct
power_supply
bat
;
struct
acpi_device
*
device
;
struct
acpi_battery_flags
flags
;
struct
acpi_buffer
bif_data
;
struct
acpi_buffer
bst_data
;
unsigned
long
alarm
;
unsigned
long
update_time
[
ACPI_BATTERY_NUMFILES
];
unsigned
long
update_time
;
int
current_now
;
int
capacity_now
;
int
voltage_now
;
int
design_capacity
;
int
full_charge_capacity
;
int
technology
;
int
design_voltage
;
int
design_capacity_warning
;
int
design_capacity_low
;
int
capacity_granularity_1
;
int
capacity_granularity_2
;
int
alarm
;
char
model_number
[
32
];
char
serial_number
[
32
];
char
type
[
32
];
char
oem_info
[
32
];
int
state
;
int
power_unit
;
u8
alarm_present
;
};
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
inline
int
acpi_battery_present
(
struct
acpi_battery
*
battery
)
{
return
battery
->
device
->
status
.
battery_present
;
}
inline
char
*
acpi_battery_power_units
(
struct
acpi_battery
*
battery
)
static
int
acpi_battery_technology
(
struct
acpi_battery
*
battery
)
{
if
(
battery
->
flags
.
power_unit
)
return
ACPI_BATTERY_UNITS_AMPS
;
else
return
ACPI_BATTERY_UNITS_WATTS
;
if
(
!
strcasecmp
(
"NiCd"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_NiCd
;
if
(
!
strcasecmp
(
"NiMH"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_NiMH
;
if
(
!
strcasecmp
(
"LION"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_LION
;
if
(
!
strcasecmp
(
"LiP"
,
battery
->
type
))
return
POWER_SUPPLY_TECHNOLOGY_LIPO
;
return
POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
}
static
int
acpi_battery_get_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
{
struct
acpi_battery
*
battery
=
to_acpi_battery
(
psy
);
if
((
!
acpi_battery_present
(
battery
))
&&
psp
!=
POWER_SUPPLY_PROP_PRESENT
)
return
-
ENODEV
;
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_STATUS
:
if
(
battery
->
state
&
0x01
)
val
->
intval
=
POWER_SUPPLY_STATUS_DISCHARGING
;
else
if
(
battery
->
state
&
0x02
)
val
->
intval
=
POWER_SUPPLY_STATUS_CHARGING
;
else
if
(
battery
->
state
==
0
)
val
->
intval
=
POWER_SUPPLY_STATUS_FULL
;
break
;
case
POWER_SUPPLY_PROP_PRESENT
:
val
->
intval
=
acpi_battery_present
(
battery
);
break
;
case
POWER_SUPPLY_PROP_TECHNOLOGY
:
val
->
intval
=
acpi_battery_technology
(
battery
);
break
;
case
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
:
val
->
intval
=
battery
->
design_voltage
*
1000
;
break
;
case
POWER_SUPPLY_PROP_VOLTAGE_NOW
:
val
->
intval
=
battery
->
voltage_now
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CURRENT_NOW
:
val
->
intval
=
battery
->
current_now
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
case
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN
:
val
->
intval
=
battery
->
design_capacity
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL
:
case
POWER_SUPPLY_PROP_ENERGY_FULL
:
val
->
intval
=
battery
->
full_charge_capacity
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_NOW
:
case
POWER_SUPPLY_PROP_ENERGY_NOW
:
val
->
intval
=
battery
->
capacity_now
*
1000
;
break
;
case
POWER_SUPPLY_PROP_MODEL_NAME
:
val
->
strval
=
battery
->
model_number
;
break
;
case
POWER_SUPPLY_PROP_MANUFACTURER
:
val
->
strval
=
battery
->
oem_info
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
inline
acpi_handle
acpi_battery_handle
(
struct
acpi_battery
*
battery
)
static
enum
power_supply_property
charge_battery_props
[]
=
{
POWER_SUPPLY_PROP_STATUS
,
POWER_SUPPLY_PROP_PRESENT
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
POWER_SUPPLY_PROP_VOLTAGE_NOW
,
POWER_SUPPLY_PROP_CURRENT_NOW
,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
POWER_SUPPLY_PROP_CHARGE_FULL
,
POWER_SUPPLY_PROP_CHARGE_NOW
,
POWER_SUPPLY_PROP_MODEL_NAME
,
POWER_SUPPLY_PROP_MANUFACTURER
,
};
static
enum
power_supply_property
energy_battery_props
[]
=
{
POWER_SUPPLY_PROP_STATUS
,
POWER_SUPPLY_PROP_PRESENT
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
POWER_SUPPLY_PROP_VOLTAGE_NOW
,
POWER_SUPPLY_PROP_CURRENT_NOW
,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN
,
POWER_SUPPLY_PROP_ENERGY_FULL
,
POWER_SUPPLY_PROP_ENERGY_NOW
,
POWER_SUPPLY_PROP_MODEL_NAME
,
POWER_SUPPLY_PROP_MANUFACTURER
,
};
#ifdef CONFIG_ACPI_PROCFS
inline
char
*
acpi_battery_units
(
struct
acpi_battery
*
battery
)
{
return
battery
->
device
->
handle
;
return
(
battery
->
power_unit
)
?
"mA"
:
"mW"
;
}
#endif
/* --------------------------------------------------------------------------
Battery Management
-------------------------------------------------------------------------- */
struct
acpi_offsets
{
size_t
offset
;
/* offset inside struct acpi_sbs_battery */
u8
mode
;
/* int or string? */
};
static
void
acpi_battery_check_result
(
struct
acpi_battery
*
battery
,
int
result
)
{
if
(
!
battery
)
return
;
static
struct
acpi_offsets
state_offsets
[]
=
{
{
offsetof
(
struct
acpi_battery
,
state
),
0
},
{
offsetof
(
struct
acpi_battery
,
current_now
),
0
},
{
offsetof
(
struct
acpi_battery
,
capacity_now
),
0
},
{
offsetof
(
struct
acpi_battery
,
voltage_now
),
0
},
};
if
(
result
)
{
battery
->
flags
.
init_update
=
1
;
}
}
static
struct
acpi_offsets
info_offsets
[]
=
{
{
offsetof
(
struct
acpi_battery
,
power_unit
),
0
},
{
offsetof
(
struct
acpi_battery
,
design_capacity
),
0
},
{
offsetof
(
struct
acpi_battery
,
full_charge_capacity
),
0
},
{
offsetof
(
struct
acpi_battery
,
technology
),
0
},
{
offsetof
(
struct
acpi_battery
,
design_voltage
),
0
},
{
offsetof
(
struct
acpi_battery
,
design_capacity_warning
),
0
},
{
offsetof
(
struct
acpi_battery
,
design_capacity_low
),
0
},
{
offsetof
(
struct
acpi_battery
,
capacity_granularity_1
),
0
},
{
offsetof
(
struct
acpi_battery
,
capacity_granularity_2
),
0
},
{
offsetof
(
struct
acpi_battery
,
model_number
),
1
},
{
offsetof
(
struct
acpi_battery
,
serial_number
),
1
},
{
offsetof
(
struct
acpi_battery
,
type
),
1
},
{
offsetof
(
struct
acpi_battery
,
oem_info
),
1
},
};
static
int
acpi_battery_
extract_package
(
struct
acpi_battery
*
battery
,
static
int
extract_package
(
struct
acpi_battery
*
battery
,
union
acpi_object
*
package
,
struct
acpi_buffer
*
format
,
struct
acpi_buffer
*
data
,
char
*
package_name
)
{
acpi_status
status
=
AE_OK
;
struct
acpi_buffer
data_null
=
{
0
,
NULL
};
status
=
acpi_extract_package
(
package
,
format
,
&
data_null
);
if
(
status
!=
AE_BUFFER_OVERFLOW
)
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Extracting size %s"
,
package_name
));
return
-
ENODEV
;
}
if
(
data_null
.
length
!=
data
->
length
)
{
kfree
(
data
->
pointer
);
data
->
pointer
=
kzalloc
(
data_null
.
length
,
GFP_KERNEL
);
if
(
!
data
->
pointer
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_NO_MEMORY
,
"kzalloc()"
));
return
-
ENOMEM
;
}
data
->
length
=
data_null
.
length
;
struct
acpi_offsets
*
offsets
,
int
num
)
{
int
i
,
*
x
;
union
acpi_object
*
element
;
if
(
package
->
type
!=
ACPI_TYPE_PACKAGE
)
return
-
EFAULT
;
for
(
i
=
0
;
i
<
num
;
++
i
)
{
if
(
package
->
package
.
count
<=
i
)
return
-
EFAULT
;
element
=
&
package
->
package
.
elements
[
i
];
if
(
offsets
[
i
].
mode
)
{
if
(
element
->
type
!=
ACPI_TYPE_STRING
&&
element
->
type
!=
ACPI_TYPE_BUFFER
)
return
-
EFAULT
;
strncpy
((
u8
*
)
battery
+
offsets
[
i
].
offset
,
element
->
string
.
pointer
,
32
);
}
else
{
if
(
element
->
type
!=
ACPI_TYPE_INTEGER
)
return
-
EFAULT
;
x
=
(
int
*
)((
u8
*
)
battery
+
offsets
[
i
].
offset
);
*
x
=
element
->
integer
.
value
;
}
status
=
acpi_extract_package
(
package
,
format
,
data
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Extracting %s"
,
package_name
));
return
-
ENODEV
;
}
return
0
;
}
static
int
acpi_battery_get_status
(
struct
acpi_battery
*
battery
)
{
int
result
=
0
;
result
=
acpi_bus_get_status
(
battery
->
device
);
if
(
result
)
{
if
(
acpi_bus_get_status
(
battery
->
device
))
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"Evaluating _STA"
));
return
-
ENODEV
;
}
return
result
;
return
0
;
}
static
int
acpi_battery_get_info
(
struct
acpi_battery
*
battery
)
{
int
result
=
0
;
int
result
=
-
EFAULT
;
acpi_status
status
=
0
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
format
=
{
sizeof
(
ACPI_BATTERY_FORMAT_BIF
),
ACPI_BATTERY_FORMAT_BIF
};
union
acpi_object
*
package
=
NULL
;
struct
acpi_buffer
*
data
=
NULL
;
struct
acpi_battery_info
*
bif
=
NULL
;
battery
->
update_time
[
ACPI_BATTERY_INFO
]
=
get_seconds
();
if
(
!
acpi_battery_present
(
battery
))
return
0
;
mutex_lock
(
&
battery
->
lock
);
status
=
acpi_evaluate_object
(
battery
->
device
->
handle
,
"_BIF"
,
NULL
,
&
buffer
);
mutex_unlock
(
&
battery
->
lock
);
/* Evaluate _BIF */
status
=
acpi_evaluate_object
(
acpi_battery_handle
(
battery
),
"_BIF"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Evaluating _BIF"
));
return
-
ENODEV
;
}
package
=
buffer
.
pointer
;
data
=
&
battery
->
bif_data
;
/* Extract Package Data */
result
=
acpi_battery_extract_package
(
battery
,
package
,
&
format
,
data
,
"_BIF"
);
if
(
result
)
goto
end
;
end:
result
=
extract_package
(
battery
,
buffer
.
pointer
,
info_offsets
,
ARRAY_SIZE
(
info_offsets
));
kfree
(
buffer
.
pointer
);
if
(
!
result
)
{
bif
=
data
->
pointer
;
battery
->
flags
.
power_unit
=
bif
->
power_unit
;
}
return
result
;
}
...
...
@@ -273,342 +319,203 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
int
result
=
0
;
acpi_status
status
=
0
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
format
=
{
sizeof
(
ACPI_BATTERY_FORMAT_BST
),
ACPI_BATTERY_FORMAT_BST
};
union
acpi_object
*
package
=
NULL
;
struct
acpi_buffer
*
data
=
NULL
;
battery
->
update_time
[
ACPI_BATTERY_STATE
]
=
get_seconds
();
if
(
!
acpi_battery_present
(
battery
))
return
0
;
/* Evaluate _BST */
if
(
battery
->
update_time
&&
time_before
(
jiffies
,
battery
->
update_time
+
msecs_to_jiffies
(
cache_time
)))
return
0
;
mutex_lock
(
&
battery
->
lock
);
status
=
acpi_evaluate_object
(
battery
->
device
->
handle
,
"_BST"
,
NULL
,
&
buffer
);
mutex_unlock
(
&
battery
->
lock
);
status
=
acpi_evaluate_object
(
acpi_battery_handle
(
battery
),
"_BST"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"Evaluating _BST"
));
return
-
ENODEV
;
}
package
=
buffer
.
pointer
;
data
=
&
battery
->
bst_data
;
/* Extract Package Data */
result
=
acpi_battery_extract_package
(
battery
,
package
,
&
format
,
data
,
"_BST"
);
if
(
result
)
goto
end
;
end:
result
=
extract_package
(
battery
,
buffer
.
pointer
,
state_offsets
,
ARRAY_SIZE
(
state_offsets
));
battery
->
update_time
=
jiffies
;
kfree
(
buffer
.
pointer
);
return
result
;
}
static
int
acpi_battery_get_alarm
(
struct
acpi_battery
*
battery
)
{
battery
->
update_time
[
ACPI_BATTERY_ALARM
]
=
get_seconds
();
return
0
;
}
static
int
acpi_battery_set_alarm
(
struct
acpi_battery
*
battery
,
unsigned
long
alarm
)
static
int
acpi_battery_set_alarm
(
struct
acpi_battery
*
battery
)
{
acpi_status
status
=
0
;
union
acpi_object
arg0
=
{
ACPI_TYPE_INTEGER
};
union
acpi_object
arg0
=
{
.
type
=
ACPI_TYPE_INTEGER
};
struct
acpi_object_list
arg_list
=
{
1
,
&
arg0
};
battery
->
update_time
[
ACPI_BATTERY_ALARM
]
=
get_seconds
();
if
(
!
acpi_battery_present
(
battery
))
return
-
ENODEV
;
if
(
!
battery
->
flags
.
alarm_present
)
if
(
!
acpi_battery_present
(
battery
)
||
!
battery
->
alarm_present
)
return
-
ENODEV
;
arg0
.
integer
.
value
=
alarm
;
arg0
.
integer
.
value
=
battery
->
alarm
;
status
=
acpi_evaluate_object
(
acpi_battery_handle
(
battery
)
,
"_BTP"
,
mutex_lock
(
&
battery
->
lock
);
status
=
acpi_evaluate_object
(
battery
->
device
->
handle
,
"_BTP"
,
&
arg_list
,
NULL
);
mutex_unlock
(
&
battery
->
lock
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Alarm set to %d
\n
"
,
(
u32
)
alarm
));
battery
->
alarm
=
alarm
;
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Alarm set to %d
\n
"
,
battery
->
alarm
));
return
0
;
}
static
int
acpi_battery_init_alarm
(
struct
acpi_battery
*
battery
)
{
int
result
=
0
;
acpi_status
status
=
AE_OK
;
acpi_handle
handle
=
NULL
;
struct
acpi_battery_info
*
bif
=
battery
->
bif_data
.
pointer
;
unsigned
long
alarm
=
battery
->
alarm
;
/* See if alarms are supported, and if so, set default */
status
=
acpi_get_handle
(
acpi_battery_handle
(
battery
),
"_BTP"
,
&
handle
);
if
(
ACPI_SUCCESS
(
status
))
{
battery
->
flags
.
alarm_present
=
1
;
if
(
!
alarm
&&
bif
)
{
alarm
=
bif
->
design_capacity_warning
;
}
result
=
acpi_battery_set_alarm
(
battery
,
alarm
);
if
(
result
)
goto
end
;
}
else
{
battery
->
flags
.
alarm_present
=
0
;
status
=
acpi_get_handle
(
battery
->
device
->
handle
,
"_BTP"
,
&
handle
);
if
(
ACPI_FAILURE
(
status
))
{
battery
->
alarm_present
=
0
;
return
0
;
}
end:
return
result
;
battery
->
alarm_present
=
1
;
if
(
!
battery
->
alarm
)
battery
->
alarm
=
battery
->
design_capacity_warning
;
return
acpi_battery_set_alarm
(
battery
)
;
}
static
int
acpi_battery_
init_
update
(
struct
acpi_battery
*
battery
)
static
int
acpi_battery_update
(
struct
acpi_battery
*
battery
)
{
int
result
=
0
;
result
=
acpi_battery_get_status
(
battery
);
if
(
result
)
int
saved_present
=
acpi_battery_present
(
battery
);
int
result
=
acpi_battery_get_status
(
battery
);
if
(
result
||
!
acpi_battery_present
(
battery
))
return
result
;
battery
->
flags
.
battery_present_prev
=
acpi_battery_present
(
battery
);
if
(
acpi_battery_present
(
battery
))
{
if
(
saved_present
!=
acpi_battery_present
(
battery
)
||
!
battery
->
update_time
)
{
battery
->
update_time
=
0
;
result
=
acpi_battery_get_info
(
battery
);
if
(
result
)
return
result
;
result
=
acpi_battery_get_state
(
battery
);
if
(
result
)
return
result
;
acpi_battery_init_alarm
(
battery
);
}
return
result
;
}
static
int
acpi_battery_update
(
struct
acpi_battery
*
battery
,
int
update
,
int
*
update_result_ptr
)
{
int
result
=
0
;
int
update_result
=
ACPI_BATTERY_NONE_UPDATE
;
if
(
!
acpi_battery_present
(
battery
))
{
update
=
1
;
}
if
(
battery
->
flags
.
init_update
)
{
result
=
acpi_battery_init_update
(
battery
);
if
(
result
)
goto
end
;
update_result
=
ACPI_BATTERY_INIT_UPDATE
;
}
else
if
(
update
)
{
result
=
acpi_battery_get_status
(
battery
);
if
(
result
)
goto
end
;
if
((
!
battery
->
flags
.
battery_present_prev
&
acpi_battery_present
(
battery
))
||
(
battery
->
flags
.
battery_present_prev
&
!
acpi_battery_present
(
battery
)))
{
result
=
acpi_battery_init_update
(
battery
);
if
(
result
)
goto
end
;
update_result
=
ACPI_BATTERY_INIT_UPDATE
;
if
(
battery
->
power_unit
)
{
battery
->
bat
.
properties
=
charge_battery_props
;
battery
->
bat
.
num_properties
=
ARRAY_SIZE
(
charge_battery_props
);
}
else
{
update_result
=
ACPI_BATTERY_EASY_UPDATE
;
}
}
end:
battery
->
flags
.
init_update
=
(
result
!=
0
);
*
update_result_ptr
=
update_result
;
return
result
;
}
static
void
acpi_battery_notify_update
(
struct
acpi_battery
*
battery
)
{
acpi_battery_get_status
(
battery
);
if
(
battery
->
flags
.
init_update
)
{
return
;
battery
->
bat
.
properties
=
energy_battery_props
;
battery
->
bat
.
num_properties
=
ARRAY_SIZE
(
energy_battery_props
);
}
if
((
!
battery
->
flags
.
battery_present_prev
&
acpi_battery_present
(
battery
))
||
(
battery
->
flags
.
battery_present_prev
&
!
acpi_battery_present
(
battery
)))
{
battery
->
flags
.
init_update
=
1
;
}
else
{
battery
->
flags
.
update
[
ACPI_BATTERY_INFO
]
=
1
;
battery
->
flags
.
update
[
ACPI_BATTERY_STATE
]
=
1
;
battery
->
flags
.
update
[
ACPI_BATTERY_ALARM
]
=
1
;
acpi_battery_init_alarm
(
battery
);
}
return
acpi_battery_get_state
(
battery
);
}
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCFS
static
struct
proc_dir_entry
*
acpi_battery_dir
;
static
int
acpi_battery_print_info
(
struct
seq_file
*
seq
,
int
result
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_battery_info
*
bif
=
NULL
;
char
*
units
=
"?"
;
if
(
result
)
goto
end
;
if
(
acpi_battery_present
(
battery
))
seq_printf
(
seq
,
"present: yes
\n
"
);
else
{
seq_printf
(
seq
,
"present: no
\n
"
);
goto
end
;
}
bif
=
battery
->
bif_data
.
pointer
;
if
(
!
bif
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"BIF buffer is NULL"
));
result
=
-
ENODEV
;
seq_printf
(
seq
,
"present: %s
\n
"
,
acpi_battery_present
(
battery
)
?
"yes"
:
"no"
);
if
(
!
acpi_battery_present
(
battery
))
goto
end
;
}
/* Battery Units */
units
=
acpi_battery_power_units
(
battery
);
if
(
bif
->
design_capacity
==
ACPI_BATTERY_VALUE_UNKNOWN
)
if
(
battery
->
design_capacity
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"design capacity: unknown
\n
"
);
else
seq_printf
(
seq
,
"design capacity: %d %sh
\n
"
,
(
u32
)
bif
->
design_capacity
,
units
);
battery
->
design_capacity
,
acpi_battery_units
(
battery
));
if
(
b
if
->
last_full
_capacity
==
ACPI_BATTERY_VALUE_UNKNOWN
)
if
(
b
attery
->
full_charge
_capacity
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"last full capacity: unknown
\n
"
);
else
seq_printf
(
seq
,
"last full capacity: %d %sh
\n
"
,
(
u32
)
bif
->
last_full_capacity
,
units
);
battery
->
full_charge_capacity
,
acpi_battery_units
(
battery
));
switch
((
u32
)
bif
->
battery_technology
)
{
case
0
:
seq_printf
(
seq
,
"battery technology: non-rechargeable
\n
"
);
break
;
case
1
:
seq_printf
(
seq
,
"battery technology: rechargeable
\n
"
);
break
;
default:
seq_printf
(
seq
,
"battery technology: unknown
\n
"
);
break
;
}
seq_printf
(
seq
,
"battery technology: %srechargeable
\n
"
,
(
!
battery
->
technology
)
?
"non-"
:
""
);
if
(
b
if
->
design_voltage
==
ACPI_BATTERY_VALUE_UNKNOWN
)
if
(
b
attery
->
design_voltage
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"design voltage: unknown
\n
"
);
else
seq_printf
(
seq
,
"design voltage: %d mV
\n
"
,
(
u32
)
bif
->
design_voltage
);
battery
->
design_voltage
);
seq_printf
(
seq
,
"design capacity warning: %d %sh
\n
"
,
(
u32
)
bif
->
design_capacity_warning
,
units
);
battery
->
design_capacity_warning
,
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"design capacity low: %d %sh
\n
"
,
(
u32
)
bif
->
design_capacity_low
,
units
);
battery
->
design_capacity_low
,
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"capacity granularity 1: %d %sh
\n
"
,
(
u32
)
bif
->
battery_capacity_granularity_1
,
units
);
battery
->
capacity_granularity_1
,
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"capacity granularity 2: %d %sh
\n
"
,
(
u32
)
bif
->
battery_capacity_granularity_2
,
units
);
seq_printf
(
seq
,
"model number: %s
\n
"
,
bif
->
model_number
);
seq_printf
(
seq
,
"
serial number: %s
\n
"
,
bif
->
seria
l_number
);
seq_printf
(
seq
,
"
battery type: %s
\n
"
,
bif
->
battery_type
);
seq_printf
(
seq
,
"
OEM info: %s
\n
"
,
bif
->
oem_info
);
battery
->
capacity_granularity_2
,
acpi_battery_units
(
battery
)
);
seq_printf
(
seq
,
"
model number: %s
\n
"
,
battery
->
mode
l_number
);
seq_printf
(
seq
,
"
serial number: %s
\n
"
,
battery
->
serial_number
);
seq_printf
(
seq
,
"
battery type: %s
\n
"
,
battery
->
type
);
seq_printf
(
seq
,
"OEM info: %s
\n
"
,
battery
->
oem_info
);
end:
if
(
result
)
seq_printf
(
seq
,
"ERROR: Unable to read battery info
\n
"
);
return
result
;
}
static
int
acpi_battery_print_state
(
struct
seq_file
*
seq
,
int
result
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_battery_state
*
bst
=
NULL
;
char
*
units
=
"?"
;
if
(
result
)
goto
end
;
if
(
acpi_battery_present
(
battery
))
seq_printf
(
seq
,
"present: yes
\n
"
);
else
{
seq_printf
(
seq
,
"present: no
\n
"
);
goto
end
;
}
bst
=
battery
->
bst_data
.
pointer
;
if
(
!
bst
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"BST buffer is NULL"
));
result
=
-
ENODEV
;
seq_printf
(
seq
,
"present: %s
\n
"
,
acpi_battery_present
(
battery
)
?
"yes"
:
"no"
);
if
(
!
acpi_battery_present
(
battery
))
goto
end
;
}
/* Battery Units */
units
=
acpi_battery_power_units
(
battery
);
if
(
!
(
bst
->
state
&
0x04
))
seq_printf
(
seq
,
"capacity state: ok
\n
"
);
else
seq_printf
(
seq
,
"capacity state: critical
\n
"
);
if
((
bst
->
state
&
0x01
)
&&
(
bst
->
state
&
0x02
))
{
seq_printf
(
seq
,
"capacity state: %s
\n
"
,
(
battery
->
state
&
0x04
)
?
"critical"
:
"ok"
);
if
((
battery
->
state
&
0x01
)
&&
(
battery
->
state
&
0x02
))
seq_printf
(
seq
,
"charging state: charging/discharging
\n
"
);
}
else
if
(
bst
->
state
&
0x01
)
else
if
(
battery
->
state
&
0x01
)
seq_printf
(
seq
,
"charging state: discharging
\n
"
);
else
if
(
b
st
->
state
&
0x02
)
else
if
(
b
attery
->
state
&
0x02
)
seq_printf
(
seq
,
"charging state: charging
\n
"
);
else
{
else
seq_printf
(
seq
,
"charging state: charged
\n
"
);
}
if
(
b
st
->
present_rate
==
ACPI_BATTERY_VALUE_UNKNOWN
)
if
(
b
attery
->
current_now
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"present rate: unknown
\n
"
);
else
seq_printf
(
seq
,
"present rate: %d %s
\n
"
,
(
u32
)
bst
->
present_rate
,
units
);
battery
->
current_now
,
acpi_battery_units
(
battery
)
);
if
(
b
st
->
remaining_capacity
==
ACPI_BATTERY_VALUE_UNKNOWN
)
if
(
b
attery
->
capacity_now
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"remaining capacity: unknown
\n
"
);
else
seq_printf
(
seq
,
"remaining capacity: %d %sh
\n
"
,
(
u32
)
bst
->
remaining_capacity
,
units
);
if
(
bst
->
present_voltage
==
ACPI_BATTERY_VALUE_UNKNOWN
)
battery
->
capacity_now
,
acpi_battery_units
(
battery
));
if
(
battery
->
voltage_now
==
ACPI_BATTERY_VALUE_UNKNOWN
)
seq_printf
(
seq
,
"present voltage: unknown
\n
"
);
else
seq_printf
(
seq
,
"present voltage: %d mV
\n
"
,
(
u32
)
bst
->
present_voltage
);
battery
->
voltage_now
);
end:
if
(
result
)
{
if
(
result
)
seq_printf
(
seq
,
"ERROR: Unable to read battery state
\n
"
);
}
return
result
;
}
...
...
@@ -616,7 +523,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)
static
int
acpi_battery_print_alarm
(
struct
seq_file
*
seq
,
int
result
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
char
*
units
=
"?"
;
if
(
result
)
goto
end
;
...
...
@@ -625,27 +531,19 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result)
seq_printf
(
seq
,
"present: no
\n
"
);
goto
end
;
}
/* Battery Units */
units
=
acpi_battery_power_units
(
battery
);
seq_printf
(
seq
,
"alarm: "
);
if
(
!
battery
->
alarm
)
seq_printf
(
seq
,
"unsupported
\n
"
);
else
seq_printf
(
seq
,
"%
lu %sh
\n
"
,
battery
->
alarm
,
units
);
seq_printf
(
seq
,
"%
u %sh
\n
"
,
battery
->
alarm
,
acpi_battery_units
(
battery
));
end:
if
(
result
)
seq_printf
(
seq
,
"ERROR: Unable to read battery alarm
\n
"
);
return
result
;
}
static
ssize_t
acpi_battery_write_alarm
(
struct
file
*
file
,
static
ssize_t
acpi_battery_write_alarm
(
struct
file
*
file
,
const
char
__user
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
...
...
@@ -653,161 +551,101 @@ acpi_battery_write_alarm(struct file *file,
char
alarm_string
[
12
]
=
{
'\0'
};
struct
seq_file
*
m
=
file
->
private_data
;
struct
acpi_battery
*
battery
=
m
->
private
;
int
update_result
=
ACPI_BATTERY_NONE_UPDATE
;
if
(
!
battery
||
(
count
>
sizeof
(
alarm_string
)
-
1
))
return
-
EINVAL
;
mutex_lock
(
&
battery
->
mutex
);
result
=
acpi_battery_update
(
battery
,
1
,
&
update_result
);
if
(
result
)
{
result
=
-
ENODEV
;
goto
end
;
}
if
(
!
acpi_battery_present
(
battery
))
{
result
=
-
ENODEV
;
goto
end
;
}
if
(
copy_from_user
(
alarm_string
,
buffer
,
count
))
{
result
=
-
EFAULT
;
goto
end
;
}
alarm_string
[
count
]
=
'\0'
;
result
=
acpi_battery_set_alarm
(
battery
,
simple_strtoul
(
alarm_string
,
NULL
,
0
));
if
(
result
)
goto
end
;
battery
->
alarm
=
simple_strtol
(
alarm_string
,
NULL
,
0
);
result
=
acpi_battery_set_alarm
(
battery
);
end:
acpi_battery_check_result
(
battery
,
result
);
if
(
!
result
)
result
=
count
;
mutex_unlock
(
&
battery
->
mutex
);
return
count
;
return
result
;
}
typedef
int
(
*
print_func
)(
struct
seq_file
*
seq
,
int
result
);
typedef
int
(
*
get_func
)(
struct
acpi_battery
*
battery
);
static
struct
acpi_read_mux
{
print_func
print
;
get_func
get
;
}
acpi_read_funcs
[
ACPI_BATTERY_NUMFILES
]
=
{
{.
get
=
acpi_battery_get_info
,
.
print
=
acpi_battery_print_info
},
{.
get
=
acpi_battery_get_state
,
.
print
=
acpi_battery_print_state
},
{.
get
=
acpi_battery_get_alarm
,
.
print
=
acpi_battery_print_alarm
},
static
print_func
acpi_print_funcs
[
ACPI_BATTERY_NUMFILES
]
=
{
acpi_battery_print_info
,
acpi_battery_print_state
,
acpi_battery_print_alarm
,
};
static
int
acpi_battery_read
(
int
fid
,
struct
seq_file
*
seq
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
int
result
=
0
;
int
update_result
=
ACPI_BATTERY_NONE_UPDATE
;
int
update
=
0
;
mutex_lock
(
&
battery
->
mutex
);
update
=
(
get_seconds
()
-
battery
->
update_time
[
fid
]
>=
update_time
);
update
=
(
update
|
battery
->
flags
.
update
[
fid
]);
result
=
acpi_battery_update
(
battery
,
update
,
&
update_result
);
if
(
result
)
goto
end
;
if
(
update_result
==
ACPI_BATTERY_EASY_UPDATE
)
{
result
=
acpi_read_funcs
[
fid
].
get
(
battery
);
if
(
result
)
goto
end
;
int
result
=
acpi_battery_update
(
battery
);
return
acpi_print_funcs
[
fid
](
seq
,
result
);
}
#define DECLARE_FILE_FUNCTIONS(_name) \
static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \
{ \
return acpi_battery_read(_name##_tag, seq); \
} \
static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \
{ \
return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \
}
DECLARE_FILE_FUNCTIONS
(
info
);
DECLARE_FILE_FUNCTIONS
(
state
);
DECLARE_FILE_FUNCTIONS
(
alarm
);
#undef DECLARE_FILE_FUNCTIONS
#define FILE_DESCRIPTION_RO(_name) \
{ \
.name = __stringify(_name), \
.mode = S_IRUGO, \
.ops = { \
.open = acpi_battery_##_name##_open_fs, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
.owner = THIS_MODULE, \
}, \
}
#define FILE_DESCRIPTION_RW(_name) \
{ \
.name = __stringify(_name), \
.mode = S_IFREG | S_IRUGO | S_IWUSR, \
.ops = { \
.open = acpi_battery_##_name##_open_fs, \
.read = seq_read, \
.llseek = seq_lseek, \
.write = acpi_battery_write_##_name, \
.release = single_release, \
.owner = THIS_MODULE, \
}, \
}
end:
result
=
acpi_read_funcs
[
fid
].
print
(
seq
,
result
);
acpi_battery_check_result
(
battery
,
result
);
battery
->
flags
.
update
[
fid
]
=
result
;
mutex_unlock
(
&
battery
->
mutex
);
return
result
;
}
static
int
acpi_battery_read_info
(
struct
seq_file
*
seq
,
void
*
offset
)
{
return
acpi_battery_read
(
ACPI_BATTERY_INFO
,
seq
);
}
static
int
acpi_battery_read_state
(
struct
seq_file
*
seq
,
void
*
offset
)
{
return
acpi_battery_read
(
ACPI_BATTERY_STATE
,
seq
);
}
static
int
acpi_battery_read_alarm
(
struct
seq_file
*
seq
,
void
*
offset
)
{
return
acpi_battery_read
(
ACPI_BATTERY_ALARM
,
seq
);
}
static
int
acpi_battery_info_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
acpi_battery_read_info
,
PDE
(
inode
)
->
data
);
}
static
int
acpi_battery_state_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
acpi_battery_read_state
,
PDE
(
inode
)
->
data
);
}
static
int
acpi_battery_alarm_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
acpi_battery_read_alarm
,
PDE
(
inode
)
->
data
);
}
static
struct
battery_file
{
struct
file_operations
ops
;
mode_t
mode
;
char
*
name
;
}
acpi_battery_file
[]
=
{
{
.
name
=
"info"
,
.
mode
=
S_IRUGO
,
.
ops
=
{
.
open
=
acpi_battery_info_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
},
},
{
.
name
=
"state"
,
.
mode
=
S_IRUGO
,
.
ops
=
{
.
open
=
acpi_battery_state_open_fs
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
},
},
{
.
name
=
"alarm"
,
.
mode
=
S_IFREG
|
S_IRUGO
|
S_IWUSR
,
.
ops
=
{
.
open
=
acpi_battery_alarm_open_fs
,
.
read
=
seq_read
,
.
write
=
acpi_battery_write_alarm
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
.
owner
=
THIS_MODULE
,
},
},
FILE_DESCRIPTION_RO
(
info
),
FILE_DESCRIPTION_RO
(
state
),
FILE_DESCRIPTION_RW
(
alarm
),
};
#undef FILE_DESCRIPTION_RO
#undef FILE_DESCRIPTION_RW
static
int
acpi_battery_add_fs
(
struct
acpi_device
*
device
)
{
struct
proc_dir_entry
*
entry
=
NULL
;
...
...
@@ -832,25 +670,51 @@ static int acpi_battery_add_fs(struct acpi_device *device)
entry
->
owner
=
THIS_MODULE
;
}
}
return
0
;
}
static
int
acpi_battery_remove_fs
(
struct
acpi_device
*
device
)
static
void
acpi_battery_remove_fs
(
struct
acpi_device
*
device
)
{
int
i
;
if
(
acpi_device_dir
(
device
))
{
for
(
i
=
0
;
i
<
ACPI_BATTERY_NUMFILES
;
++
i
)
{
if
(
!
acpi_device_dir
(
device
))
return
;
for
(
i
=
0
;
i
<
ACPI_BATTERY_NUMFILES
;
++
i
)
remove_proc_entry
(
acpi_battery_file
[
i
].
name
,
acpi_device_dir
(
device
));
}
remove_proc_entry
(
acpi_device_bid
(
device
),
acpi_battery_dir
);
acpi_device_dir
(
device
)
=
NULL
;
}
}
return
0
;
#endif
static
ssize_t
acpi_battery_alarm_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
return
sprintf
(
buf
,
"%d
\n
"
,
battery
->
alarm
*
1000
);
}
static
ssize_t
acpi_battery_alarm_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
unsigned
long
x
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
if
(
sscanf
(
buf
,
"%ld
\n
"
,
&
x
)
==
1
)
battery
->
alarm
=
x
/
1000
;
if
(
acpi_battery_present
(
battery
))
acpi_battery_set_alarm
(
battery
);
return
count
;
}
static
struct
device_attribute
alarm_attr
=
{
.
attr
=
{.
name
=
"alarm"
,
.
mode
=
0644
,
.
owner
=
THIS_MODULE
},
.
show
=
acpi_battery_alarm_show
,
.
store
=
acpi_battery_alarm_store
,
};
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
...
...
@@ -858,33 +722,17 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
static
void
acpi_battery_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
struct
acpi_battery
*
battery
=
data
;
struct
acpi_device
*
device
=
NULL
;
struct
acpi_device
*
device
;
if
(
!
battery
)
return
;
device
=
battery
->
device
;
switch
(
event
)
{
case
ACPI_BATTERY_NOTIFY_STATUS
:
case
ACPI_BATTERY_NOTIFY_INFO
:
case
ACPI_NOTIFY_BUS_CHECK
:
case
ACPI_NOTIFY_DEVICE_CHECK
:
device
=
battery
->
device
;
acpi_battery_notify_update
(
battery
);
acpi_battery_update
(
battery
);
acpi_bus_generate_proc_event
(
device
,
event
,
acpi_battery_present
(
battery
));
acpi_bus_generate_netlink_event
(
device
->
pnp
.
device_class
,
device
->
dev
.
bus_id
,
event
,
acpi_battery_present
(
battery
));
break
;
default:
ACPI_DEBUG_PRINT
((
ACPI_DB_INFO
,
"Unsupported event [0x%x]
\n
"
,
event
));
break
;
}
return
;
kobject_uevent
(
&
battery
->
bat
.
dev
->
kobj
,
KOBJ_CHANGE
);
}
static
int
acpi_battery_add
(
struct
acpi_device
*
device
)
...
...
@@ -892,33 +740,27 @@ static int acpi_battery_add(struct acpi_device *device)
int
result
=
0
;
acpi_status
status
=
0
;
struct
acpi_battery
*
battery
=
NULL
;
if
(
!
device
)
return
-
EINVAL
;
battery
=
kzalloc
(
sizeof
(
struct
acpi_battery
),
GFP_KERNEL
);
if
(
!
battery
)
return
-
ENOMEM
;
mutex_init
(
&
battery
->
mutex
);
mutex_lock
(
&
battery
->
mutex
);
battery
->
device
=
device
;
strcpy
(
acpi_device_name
(
device
),
ACPI_BATTERY_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ACPI_BATTERY_CLASS
);
acpi_driver_data
(
device
)
=
battery
;
result
=
acpi_battery_get_status
(
battery
);
if
(
result
)
goto
end
;
battery
->
flags
.
init_update
=
1
;
mutex_init
(
&
battery
->
lock
);
acpi_battery_update
(
battery
);
#ifdef CONFIG_ACPI_PROCFS
result
=
acpi_battery_add_fs
(
device
);
if
(
result
)
goto
end
;
#endif
battery
->
bat
.
name
=
acpi_device_bid
(
device
);
battery
->
bat
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
battery
->
bat
.
get_property
=
acpi_battery_get_property
;
result
=
power_supply_register
(
&
battery
->
device
->
dev
,
&
battery
->
bat
);
result
=
device_create_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
status
=
acpi_install_notify_handler
(
device
->
handle
,
ACPI_ALL_NOTIFY
,
acpi_battery_notify
,
battery
);
...
...
@@ -927,20 +769,16 @@ static int acpi_battery_add(struct acpi_device *device)
result
=
-
ENODEV
;
goto
end
;
}
printk
(
KERN_INFO
PREFIX
"%s Slot [%s] (battery %s)
\n
"
,
ACPI_BATTERY_DEVICE_NAME
,
acpi_device_bid
(
device
),
device
->
status
.
battery_present
?
"present"
:
"absent"
);
end:
if
(
result
)
{
#ifdef CONFIG_ACPI_PROCFS
acpi_battery_remove_fs
(
device
);
#endif
kfree
(
battery
);
}
mutex_unlock
(
&
battery
->
mutex
);
return
result
;
}
...
...
@@ -951,27 +789,19 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
if
(
!
device
||
!
acpi_driver_data
(
device
))
return
-
EINVAL
;
battery
=
acpi_driver_data
(
device
);
mutex_lock
(
&
battery
->
mutex
);
status
=
acpi_remove_notify_handler
(
device
->
handle
,
ACPI_ALL_NOTIFY
,
acpi_battery_notify
);
#ifdef CONFIG_ACPI_PROCFS
acpi_battery_remove_fs
(
device
);
kfree
(
battery
->
bif_data
.
pointer
);
kfree
(
battery
->
bst_data
.
pointer
);
mutex_unlock
(
&
battery
->
mutex
);
mutex_destroy
(
&
battery
->
mutex
);
#endif
if
(
battery
->
bat
.
dev
)
{
device_remove_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
power_supply_unregister
(
&
battery
->
bat
);
}
mutex_destroy
(
&
battery
->
lock
);
kfree
(
battery
);
return
0
;
}
...
...
@@ -979,44 +809,48 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
static
int
acpi_battery_resume
(
struct
acpi_device
*
device
)
{
struct
acpi_battery
*
battery
;
if
(
!
device
)
return
-
EINVAL
;
battery
=
device
->
driver_data
;
battery
->
flags
.
init_update
=
1
;
battery
=
acpi_driver_data
(
device
);
battery
->
update_time
=
0
;
return
0
;
}
static
struct
acpi_driver
acpi_battery_driver
=
{
.
name
=
"battery"
,
.
class
=
ACPI_BATTERY_CLASS
,
.
ids
=
battery_device_ids
,
.
ops
=
{
.
add
=
acpi_battery_add
,
.
resume
=
acpi_battery_resume
,
.
remove
=
acpi_battery_remove
,
},
};
static
int
__init
acpi_battery_init
(
void
)
{
int
result
;
if
(
acpi_disabled
)
return
-
ENODEV
;
#ifdef CONFIG_ACPI_PROCFS
acpi_battery_dir
=
acpi_lock_battery_dir
();
if
(
!
acpi_battery_dir
)
return
-
ENODEV
;
result
=
acpi_bus_register_driver
(
&
acpi_battery_driver
);
if
(
result
<
0
)
{
#endif
if
(
acpi_bus_register_driver
(
&
acpi_battery_driver
)
<
0
)
{
#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_battery_dir
(
acpi_battery_dir
);
#endif
return
-
ENODEV
;
}
return
0
;
}
static
void
__exit
acpi_battery_exit
(
void
)
{
acpi_bus_unregister_driver
(
&
acpi_battery_driver
);
#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_battery_dir
(
acpi_battery_dir
);
return
;
#endif
}
module_init
(
acpi_battery_init
);
...
...
drivers/acpi/bus.c
View file @
e270051d
...
...
@@ -284,15 +284,11 @@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
extern
int
event_is_open
;
int
acpi_bus_generate_proc_event
(
struct
acpi_device
*
device
,
u8
type
,
int
data
)
int
acpi_bus_generate_proc_event
4
(
const
char
*
device_class
,
const
char
*
bus_id
,
u8
type
,
int
data
)
{
struct
acpi_bus_event
*
event
=
NULL
;
struct
acpi_bus_event
*
event
;
unsigned
long
flags
=
0
;
if
(
!
device
)
return
-
EINVAL
;
/* drop event on the floor if no one's listening */
if
(
!
event_is_open
)
return
0
;
...
...
@@ -301,8 +297,8 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
if
(
!
event
)
return
-
ENOMEM
;
strcpy
(
event
->
device_class
,
device
->
pnp
.
device
_class
);
strcpy
(
event
->
bus_id
,
device
->
pnp
.
bus_id
);
strcpy
(
event
->
device_class
,
device_class
);
strcpy
(
event
->
bus_id
,
bus_id
);
event
->
type
=
type
;
event
->
data
=
data
;
...
...
@@ -313,6 +309,17 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
wake_up_interruptible
(
&
acpi_bus_event_queue
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
acpi_bus_generate_proc_event4
);
int
acpi_bus_generate_proc_event
(
struct
acpi_device
*
device
,
u8
type
,
int
data
)
{
if
(
!
device
)
return
-
EINVAL
;
return
acpi_bus_generate_proc_event4
(
device
->
pnp
.
device_class
,
device
->
pnp
.
bus_id
,
type
,
data
);
}
EXPORT_SYMBOL
(
acpi_bus_generate_proc_event
);
...
...
drivers/acpi/ec.c
View file @
e270051d
...
...
@@ -425,7 +425,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
handler
->
func
=
func
;
handler
->
data
=
data
;
mutex_lock
(
&
ec
->
lock
);
list_add
_tail
(
&
handler
->
node
,
&
ec
->
list
);
list_add
(
&
handler
->
node
,
&
ec
->
list
);
mutex_unlock
(
&
ec
->
lock
);
return
0
;
}
...
...
@@ -440,7 +440,6 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
if
(
query_bit
==
handler
->
query_bit
)
{
list_del
(
&
handler
->
node
);
kfree
(
handler
);
break
;
}
}
mutex_unlock
(
&
ec
->
lock
);
...
...
drivers/acpi/sbs.c
View file @
e270051d
/*
*
acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16
$)
*
sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0
$)
*
* Copyright (c) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
* Copyright (c) 2005-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
* Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
...
@@ -26,15 +28,22 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#endif
#include <linux/acpi.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
#define ACPI_SBS_COMPONENT 0x00080000
#include <linux/power_supply.h>
#include "sbshc.h"
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
...
...
@@ -44,56 +53,23 @@
#define ACPI_SBS_FILE_ALARM "alarm"
#define ACPI_BATTERY_DIR_NAME "BAT%i"
#define ACPI_AC_DIR_NAME "AC0"
#define ACPI_SBC_SMBUS_ADDR 0x9
#define ACPI_SBSM_SMBUS_ADDR 0xa
#define ACPI_SB_SMBUS_ADDR 0xb
#define ACPI_SBS_AC_NOTIFY_STATUS 0x80
#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81
#define _COMPONENT ACPI_SBS_COMPONENT
enum
acpi_sbs_device_addr
{
ACPI_SBS_CHARGER
=
0x9
,
ACPI_SBS_MANAGER
=
0xa
,
ACPI_SBS_BATTERY
=
0xb
,
};
ACPI_MODULE_NAME
(
"sbs"
);
#define ACPI_SBS_NOTIFY_STATUS 0x80
#define ACPI_SBS_NOTIFY_INFO 0x81
MODULE_AUTHOR
(
"
Rich Townsend
"
);
MODULE_AUTHOR
(
"
Alexey Starikovskiy <astarikovskiy@suse.de>
"
);
MODULE_DESCRIPTION
(
"Smart Battery System ACPI interface driver"
);
MODULE_LICENSE
(
"GPL"
);
#define xmsleep(t) msleep(t)
#define ACPI_EC_SMB_PRTCL 0x00
/* protocol, PEC */
#define ACPI_EC_SMB_STS 0x01
/* status */
#define ACPI_EC_SMB_ADDR 0x02
/* address */
#define ACPI_EC_SMB_CMD 0x03
/* command */
#define ACPI_EC_SMB_DATA 0x04
/* 32 data registers */
#define ACPI_EC_SMB_BCNT 0x24
/* number of data bytes */
#define ACPI_EC_SMB_STS_DONE 0x80
#define ACPI_EC_SMB_STS_STATUS 0x1f
#define ACPI_EC_SMB_PRTCL_WRITE 0x00
#define ACPI_EC_SMB_PRTCL_READ 0x01
#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
#define ACPI_EC_SMB_ACCESS_SLEEP1 1
#define ACPI_EC_SMB_ACCESS_SLEEP2 10
#define DEF_CAPACITY_UNIT 3
#define MAH_CAPACITY_UNIT 1
#define MWH_CAPACITY_UNIT 2
#define CAPACITY_UNIT DEF_CAPACITY_UNIT
#define REQUEST_UPDATE_MODE 1
#define QUEUE_UPDATE_MODE 2
#define DATA_TYPE_COMMON 0
#define DATA_TYPE_INFO 1
#define DATA_TYPE_STATE 2
#define DATA_TYPE_ALARM 3
#define DATA_TYPE_AC_STATE 4
static
unsigned
int
cache_time
=
1000
;
module_param
(
cache_time
,
uint
,
0644
);
MODULE_PARM_DESC
(
cache_time
,
"cache time in milliseconds"
);
extern
struct
proc_dir_entry
*
acpi_lock_ac_dir
(
void
);
extern
struct
proc_dir_entry
*
acpi_lock_battery_dir
(
void
);
...
...
@@ -103,764 +79,399 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
#define MAX_SBS_BAT 4
#define ACPI_SBS_BLOCK_MAX 32
#define ACPI_SBS_SMBUS_READ 1
#define ACPI_SBS_SMBUS_WRITE 2
#define ACPI_SBS_WORD_DATA 1
#define ACPI_SBS_BLOCK_DATA 2
#define UPDATE_DELAY 10
/* 0 - every time, > 0 - by update_time */
static
unsigned
int
update_time
=
120
;
static
unsigned
int
capacity_mode
=
CAPACITY_UNIT
;
module_param
(
update_time
,
uint
,
0644
);
module_param
(
capacity_mode
,
uint
,
0444
);
static
int
acpi_sbs_add
(
struct
acpi_device
*
device
);
static
int
acpi_sbs_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_sbs_resume
(
struct
acpi_device
*
device
);
static
const
struct
acpi_device_id
sbs_device_ids
[]
=
{
{
"ACPI0001"
,
0
},
{
"ACPI0005"
,
0
},
{
"ACPI0002"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
sbs_device_ids
);
static
struct
acpi_driver
acpi_sbs_driver
=
{
.
name
=
"sbs"
,
.
class
=
ACPI_SBS_CLASS
,
.
ids
=
sbs_device_ids
,
.
ops
=
{
.
add
=
acpi_sbs_add
,
.
remove
=
acpi_sbs_remove
,
.
resume
=
acpi_sbs_resume
,
},
};
struct
acpi_ac
{
int
ac_present
;
};
struct
acpi_battery_info
{
int
capacity_mode
;
s16
full_charge_capacity
;
s16
design_capacity
;
s16
design_voltage
;
int
vscale
;
int
ipscale
;
s16
serial_number
;
char
manufacturer_name
[
ACPI_SBS_BLOCK_MAX
+
3
];
char
device_name
[
ACPI_SBS_BLOCK_MAX
+
3
];
char
device_chemistry
[
ACPI_SBS_BLOCK_MAX
+
3
];
};
struct
acpi_battery_state
{
s16
voltage
;
s16
amperage
;
s16
remaining_capacity
;
s16
battery_state
;
};
struct
acpi_battery_alarm
{
s16
remaining_capacity
;
};
struct
acpi_battery
{
int
alive
;
int
id
;
int
init_state
;
int
battery_present
;
struct
power_supply
bat
;
struct
acpi_sbs
*
sbs
;
struct
acpi_battery_info
info
;
struct
acpi_battery_state
state
;
struct
acpi_battery_alarm
alarm
;
struct
proc_dir_entry
*
battery_entry
;
#ifdef CONFIG_ACPI_PROCFS
struct
proc_dir_entry
*
proc_entry
;
#endif
unsigned
long
update_time
;
char
name
[
8
];
char
manufacturer_name
[
ACPI_SBS_BLOCK_MAX
];
char
device_name
[
ACPI_SBS_BLOCK_MAX
];
char
device_chemistry
[
ACPI_SBS_BLOCK_MAX
];
u16
alarm_capacity
;
u16
full_charge_capacity
;
u16
design_capacity
;
u16
design_voltage
;
u16
serial_number
;
u16
cycle_count
;
u16
temp_now
;
u16
voltage_now
;
s16
current_now
;
s16
current_avg
;
u16
capacity_now
;
u16
state_of_charge
;
u16
state
;
u16
mode
;
u16
spec
;
u8
id
;
u8
present
:
1
;
};
#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
struct
acpi_sbs
{
int
base
;
struct
power_supply
charger
;
struct
acpi_device
*
device
;
struct
mutex
mutex
;
int
sbsm_present
;
int
sbsm_batteries_supported
;
struct
proc_dir_entry
*
ac
_entry
;
struct
acpi_ac
ac
;
struct
acpi_smb_hc
*
hc
;
struct
mutex
lock
;
#ifdef CONFIG_ACPI_PROCFS
struct
proc_dir_entry
*
charger
_entry
;
#endif
struct
acpi_battery
battery
[
MAX_SBS_BAT
];
int
zombie
;
struct
timer_list
update_timer
;
int
run_cnt
;
int
update_proc_flg
;
u8
batteries_supported
:
4
;
u8
manager_present
:
1
;
u8
charger_present
:
1
;
};
static
int
acpi_sbs_update_run
(
struct
acpi_sbs
*
sbs
,
int
id
,
int
data_type
);
static
void
acpi_sbs_update_time
(
void
*
data
);
union
sbs_rw_data
{
u16
word
;
u8
block
[
ACPI_SBS_BLOCK_MAX
+
2
];
};
static
int
acpi_ec_sbs_access
(
struct
acpi_sbs
*
sbs
,
u16
addr
,
char
read_write
,
u8
command
,
int
size
,
union
sbs_rw_data
*
data
);
/* --------------------------------------------------------------------------
SMBus Communication
-------------------------------------------------------------------------- */
static
int
acpi_ec_sbs_read
(
struct
acpi_sbs
*
sbs
,
u8
address
,
u8
*
data
)
{
u8
val
;
int
err
;
err
=
ec_read
(
sbs
->
base
+
address
,
&
val
);
if
(
!
err
)
{
*
data
=
val
;
}
xmsleep
(
ACPI_EC_SMB_TRANSACTION_SLEEP
);
return
(
err
);
}
static
int
acpi_ec_sbs_write
(
struct
acpi_sbs
*
sbs
,
u8
address
,
u8
data
)
{
int
err
;
#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
err
=
ec_write
(
sbs
->
base
+
address
,
data
);
return
(
err
);
}
static
int
acpi_ec_sbs_access
(
struct
acpi_sbs
*
sbs
,
u16
addr
,
char
read_write
,
u8
command
,
int
size
,
union
sbs_rw_data
*
data
)
static
inline
int
battery_scale
(
int
log
)
{
unsigned
char
protocol
,
len
=
0
,
temp
[
2
]
=
{
0
,
0
};
int
i
;
if
(
read_write
==
ACPI_SBS_SMBUS_READ
)
{
protocol
=
ACPI_EC_SMB_PRTCL_READ
;
}
else
{
protocol
=
ACPI_EC_SMB_PRTCL_WRITE
;
}
switch
(
size
)
{
case
ACPI_SBS_WORD_DATA
:
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_CMD
,
command
);
if
(
read_write
==
ACPI_SBS_SMBUS_WRITE
)
{
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_DATA
,
data
->
word
);
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_DATA
+
1
,
data
->
word
>>
8
);
}
protocol
|=
ACPI_EC_SMB_PRTCL_WORD_DATA
;
break
;
case
ACPI_SBS_BLOCK_DATA
:
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_CMD
,
command
);
if
(
read_write
==
ACPI_SBS_SMBUS_WRITE
)
{
len
=
min_t
(
u8
,
data
->
block
[
0
],
32
);
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_BCNT
,
len
);
for
(
i
=
0
;
i
<
len
;
i
++
)
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_DATA
+
i
,
data
->
block
[
i
+
1
]);
}
protocol
|=
ACPI_EC_SMB_PRTCL_BLOCK_DATA
;
break
;
default:
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"unsupported transaction %d"
,
size
));
return
(
-
1
);
}
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_ADDR
,
addr
<<
1
);
acpi_ec_sbs_write
(
sbs
,
ACPI_EC_SMB_PRTCL
,
protocol
);
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_STS
,
temp
);
if
(
~
temp
[
0
]
&
ACPI_EC_SMB_STS_DONE
)
{
xmsleep
(
ACPI_EC_SMB_ACCESS_SLEEP1
);
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_STS
,
temp
);
}
if
(
~
temp
[
0
]
&
ACPI_EC_SMB_STS_DONE
)
{
xmsleep
(
ACPI_EC_SMB_ACCESS_SLEEP2
);
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_STS
,
temp
);
}
if
((
~
temp
[
0
]
&
ACPI_EC_SMB_STS_DONE
)
||
(
temp
[
0
]
&
ACPI_EC_SMB_STS_STATUS
))
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"transaction %d error"
,
size
));
return
(
-
1
);
}
if
(
read_write
==
ACPI_SBS_SMBUS_WRITE
)
{
return
(
0
);
}
switch
(
size
)
{
case
ACPI_SBS_WORD_DATA
:
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_DATA
,
temp
);
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_DATA
+
1
,
temp
+
1
);
data
->
word
=
(
temp
[
1
]
<<
8
)
|
temp
[
0
];
break
;
case
ACPI_SBS_BLOCK_DATA
:
len
=
0
;
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_BCNT
,
&
len
);
len
=
min_t
(
u8
,
len
,
32
);
for
(
i
=
0
;
i
<
len
;
i
++
)
acpi_ec_sbs_read
(
sbs
,
ACPI_EC_SMB_DATA
+
i
,
data
->
block
+
i
+
1
);
data
->
block
[
0
]
=
len
;
break
;
default:
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"unsupported transaction %d"
,
size
));
return
(
-
1
);
}
return
(
0
);
int
scale
=
1
;
while
(
log
--
)
scale
*=
10
;
return
scale
;
}
static
int
acpi_sbs_read_word
(
struct
acpi_sbs
*
sbs
,
int
addr
,
int
func
,
u16
*
word
)
static
inline
int
acpi_battery_vscale
(
struct
acpi_battery
*
battery
)
{
union
sbs_rw_data
data
;
int
result
=
0
;
result
=
acpi_ec_sbs_access
(
sbs
,
addr
,
ACPI_SBS_SMBUS_READ
,
func
,
ACPI_SBS_WORD_DATA
,
&
data
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ec_sbs_access() failed"
));
}
else
{
*
word
=
data
.
word
;
}
return
result
;
return
battery_scale
((
battery
->
spec
&
0x0f00
)
>>
8
);
}
static
int
acpi_sbs_read_str
(
struct
acpi_sbs
*
sbs
,
int
addr
,
int
func
,
char
*
str
)
static
inline
int
acpi_battery_ipscale
(
struct
acpi_battery
*
battery
)
{
union
sbs_rw_data
data
;
int
result
=
0
;
result
=
acpi_ec_sbs_access
(
sbs
,
addr
,
ACPI_SBS_SMBUS_READ
,
func
,
ACPI_SBS_BLOCK_DATA
,
&
data
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ec_sbs_access() failed"
));
}
else
{
strncpy
(
str
,
(
const
char
*
)
data
.
block
+
1
,
data
.
block
[
0
]);
str
[
data
.
block
[
0
]]
=
0
;
}
return
result
;
return
battery_scale
((
battery
->
spec
&
0xf000
)
>>
12
);
}
static
int
acpi_sbs_write_word
(
struct
acpi_sbs
*
sbs
,
int
addr
,
int
func
,
int
word
)
static
inline
int
acpi_battery_mode
(
struct
acpi_battery
*
battery
)
{
union
sbs_rw_data
data
;
int
result
=
0
;
data
.
word
=
word
;
result
=
acpi_ec_sbs_access
(
sbs
,
addr
,
ACPI_SBS_SMBUS_WRITE
,
func
,
ACPI_SBS_WORD_DATA
,
&
data
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ec_sbs_access() failed"
));
}
return
result
;
return
(
battery
->
mode
&
0x8000
);
}
static
in
t
sbs_zombie
(
struct
acpi_sbs
*
sbs
)
static
in
line
int
acpi_battery_scale
(
struct
acpi_battery
*
battery
)
{
return
(
sbs
->
zombie
);
return
(
acpi_battery_mode
(
battery
)
?
10
:
1
)
*
acpi_battery_ipscale
(
battery
);
}
static
int
sbs_mutex_lock
(
struct
acpi_sbs
*
sbs
)
static
int
sbs_get_ac_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
{
if
(
sbs_zombie
(
sbs
))
{
return
-
ENODEV
;
struct
acpi_sbs
*
sbs
=
to_acpi_sbs
(
psy
);
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_ONLINE
:
val
->
intval
=
sbs
->
charger_present
;
break
;
default:
return
-
EINVAL
;
}
mutex_lock
(
&
sbs
->
mutex
);
return
0
;
}
static
void
sbs_mutex_unlock
(
struct
acpi_sbs
*
sbs
)
static
int
acpi_battery_technology
(
struct
acpi_battery
*
battery
)
{
mutex_unlock
(
&
sbs
->
mutex
);
if
(
!
strcasecmp
(
"NiCd"
,
battery
->
device_chemistry
))
return
POWER_SUPPLY_TECHNOLOGY_NiCd
;
if
(
!
strcasecmp
(
"NiMH"
,
battery
->
device_chemistry
))
return
POWER_SUPPLY_TECHNOLOGY_NiMH
;
if
(
!
strcasecmp
(
"LION"
,
battery
->
device_chemistry
))
return
POWER_SUPPLY_TECHNOLOGY_LION
;
if
(
!
strcasecmp
(
"LiP"
,
battery
->
device_chemistry
))
return
POWER_SUPPLY_TECHNOLOGY_LIPO
;
return
POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
}
/* --------------------------------------------------------------------------
Smart Battery System Management
-------------------------------------------------------------------------- */
static
int
acpi_check_update_proc
(
struct
acpi_sbs
*
sbs
)
static
int
acpi_sbs_battery_get_property
(
struct
power_supply
*
psy
,
enum
power_supply_property
psp
,
union
power_supply_propval
*
val
)
{
acpi_status
status
=
AE_OK
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
psy
)
;
if
(
update_time
==
0
)
{
sbs
->
update_proc_flg
=
0
;
return
0
;
}
if
(
sbs
->
update_proc_flg
==
0
)
{
status
=
acpi_os_execute
(
OSL_GPE_HANDLER
,
acpi_sbs_update_time
,
sbs
);
if
(
status
!=
AE_OK
)
{
ACPI_EXCEPTION
((
AE_INFO
,
status
,
"acpi_os_execute() failed"
));
return
1
;
}
sbs
->
update_proc_flg
=
1
;
if
((
!
battery
->
present
)
&&
psp
!=
POWER_SUPPLY_PROP_PRESENT
)
return
-
ENODEV
;
switch
(
psp
)
{
case
POWER_SUPPLY_PROP_STATUS
:
if
(
battery
->
current_now
<
0
)
val
->
intval
=
POWER_SUPPLY_STATUS_DISCHARGING
;
else
if
(
battery
->
current_now
>
0
)
val
->
intval
=
POWER_SUPPLY_STATUS_CHARGING
;
else
val
->
intval
=
POWER_SUPPLY_STATUS_FULL
;
break
;
case
POWER_SUPPLY_PROP_PRESENT
:
val
->
intval
=
battery
->
present
;
break
;
case
POWER_SUPPLY_PROP_TECHNOLOGY
:
val
->
intval
=
acpi_battery_technology
(
battery
);
break
;
case
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
:
val
->
intval
=
battery
->
design_voltage
*
acpi_battery_vscale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_VOLTAGE_NOW
:
val
->
intval
=
battery
->
voltage_now
*
acpi_battery_vscale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CURRENT_NOW
:
val
->
intval
=
abs
(
battery
->
current_now
)
*
acpi_battery_ipscale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CURRENT_AVG
:
val
->
intval
=
abs
(
battery
->
current_avg
)
*
acpi_battery_ipscale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CAPACITY
:
val
->
intval
=
battery
->
state_of_charge
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
case
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN
:
val
->
intval
=
battery
->
design_capacity
*
acpi_battery_scale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_FULL
:
case
POWER_SUPPLY_PROP_ENERGY_FULL
:
val
->
intval
=
battery
->
full_charge_capacity
*
acpi_battery_scale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_CHARGE_NOW
:
case
POWER_SUPPLY_PROP_ENERGY_NOW
:
val
->
intval
=
battery
->
capacity_now
*
acpi_battery_scale
(
battery
)
*
1000
;
break
;
case
POWER_SUPPLY_PROP_TEMP
:
val
->
intval
=
battery
->
temp_now
-
2730
;
// dK -> dC
break
;
case
POWER_SUPPLY_PROP_MODEL_NAME
:
val
->
strval
=
battery
->
device_name
;
break
;
case
POWER_SUPPLY_PROP_MANUFACTURER
:
val
->
strval
=
battery
->
manufacturer_name
;
break
;
default:
return
-
EINVAL
;
}
return
0
;
}
static
int
acpi_sbs_generate_event
(
struct
acpi_device
*
device
,
int
event
,
int
state
,
char
*
bid
,
char
*
class
)
{
char
bid_saved
[
5
];
char
class_saved
[
20
];
int
result
=
0
;
strcpy
(
bid_saved
,
acpi_device_bid
(
device
));
strcpy
(
class_saved
,
acpi_device_class
(
device
));
strcpy
(
acpi_device_bid
(
device
),
bid
);
strcpy
(
acpi_device_class
(
device
),
class
);
result
=
acpi_bus_generate_proc_event
(
device
,
event
,
state
);
strcpy
(
acpi_device_bid
(
device
),
bid_saved
);
strcpy
(
acpi_device_class
(
device
),
class_saved
);
acpi_bus_generate_netlink_event
(
class
,
bid
,
event
,
state
);
return
result
;
}
static
int
acpi_battery_get_present
(
struct
acpi_battery
*
battery
)
{
s16
state
;
int
result
=
0
;
int
is_present
=
0
;
result
=
acpi_sbs_read_word
(
battery
->
sbs
,
ACPI_SBSM_SMBUS_ADDR
,
0x01
,
&
state
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
}
if
(
!
result
)
{
is_present
=
(
state
&
0x000f
)
&
(
1
<<
battery
->
id
);
}
battery
->
battery_present
=
is_present
;
return
result
;
}
static
enum
power_supply_property
sbs_ac_props
[]
=
{
POWER_SUPPLY_PROP_ONLINE
,
};
static
int
acpi_battery_select
(
struct
acpi_battery
*
battery
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
s16
state
;
int
foo
;
static
enum
power_supply_property
sbs_charge_battery_props
[]
=
{
POWER_SUPPLY_PROP_STATUS
,
POWER_SUPPLY_PROP_PRESENT
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
POWER_SUPPLY_PROP_VOLTAGE_NOW
,
POWER_SUPPLY_PROP_CURRENT_NOW
,
POWER_SUPPLY_PROP_CURRENT_AVG
,
POWER_SUPPLY_PROP_CAPACITY
,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
POWER_SUPPLY_PROP_CHARGE_FULL
,
POWER_SUPPLY_PROP_CHARGE_NOW
,
POWER_SUPPLY_PROP_TEMP
,
POWER_SUPPLY_PROP_MODEL_NAME
,
POWER_SUPPLY_PROP_MANUFACTURER
,
};
if
(
sbs
->
sbsm_present
)
{
static
enum
power_supply_property
sbs_energy_battery_props
[]
=
{
POWER_SUPPLY_PROP_STATUS
,
POWER_SUPPLY_PROP_PRESENT
,
POWER_SUPPLY_PROP_TECHNOLOGY
,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN
,
POWER_SUPPLY_PROP_VOLTAGE_NOW
,
POWER_SUPPLY_PROP_CURRENT_NOW
,
POWER_SUPPLY_PROP_CURRENT_AVG
,
POWER_SUPPLY_PROP_CAPACITY
,
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN
,
POWER_SUPPLY_PROP_ENERGY_FULL
,
POWER_SUPPLY_PROP_ENERGY_NOW
,
POWER_SUPPLY_PROP_TEMP
,
POWER_SUPPLY_PROP_MODEL_NAME
,
POWER_SUPPLY_PROP_MANUFACTURER
,
};
/* Take special care not to knobble other nibbles of
* state (aka selector_state), since
* it causes charging to halt on SBSELs
*/
/* --------------------------------------------------------------------------
Smart Battery System Management
--------------------------------------------------------------------------
*/
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SBSM_SMBUS_ADDR
,
0x01
,
&
state
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
struct
acpi_battery_reader
{
u8
command
;
/* command for battery */
u8
mode
;
/* word or block? */
size_t
offset
;
/* offset inside struct acpi_sbs_battery */
};
foo
=
(
state
&
0x0fff
)
|
(
1
<<
(
battery
->
id
+
12
));
result
=
acpi_sbs_write_word
(
sbs
,
ACPI_SBSM_SMBUS_ADDR
,
0x01
,
foo
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_write_word() failed"
));
goto
end
;
}
}
static
struct
acpi_battery_reader
info_readers
[]
=
{
{
0x01
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
alarm_capacity
)},
{
0x03
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
mode
)},
{
0x10
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
full_charge_capacity
)},
{
0x17
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
cycle_count
)},
{
0x18
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
design_capacity
)},
{
0x19
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
design_voltage
)},
{
0x1a
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
spec
)},
{
0x1c
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
serial_number
)},
{
0x20
,
SMBUS_READ_BLOCK
,
offsetof
(
struct
acpi_battery
,
manufacturer_name
)},
{
0x21
,
SMBUS_READ_BLOCK
,
offsetof
(
struct
acpi_battery
,
device_name
)},
{
0x22
,
SMBUS_READ_BLOCK
,
offsetof
(
struct
acpi_battery
,
device_chemistry
)},
};
end:
return
result
;
}
static
struct
acpi_battery_reader
state_readers
[]
=
{
{
0x08
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
temp_now
)},
{
0x09
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
voltage_now
)},
{
0x0a
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
current_now
)},
{
0x0b
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
current_avg
)},
{
0x0f
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
capacity_now
)},
{
0x0e
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
state_of_charge
)},
{
0x16
,
SMBUS_READ_WORD
,
offsetof
(
struct
acpi_battery
,
state
)},
};
static
int
acpi_
sbsm
_get_info
(
struct
acpi_sbs
*
sbs
)
static
int
acpi_
manager
_get_info
(
struct
acpi_sbs
*
sbs
)
{
int
result
=
0
;
s16
battery_system_info
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SBSM_SMBUS_ADDR
,
0x04
,
&
battery_system_info
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
sbs
->
sbsm_present
=
1
;
sbs
->
sbsm_batteries_supported
=
battery_system_info
&
0x000f
;
end:
u16
battery_system_info
;
result
=
acpi_smbus_read
(
sbs
->
hc
,
SMBUS_READ_WORD
,
ACPI_SBS_MANAGER
,
0x04
,
(
u8
*
)
&
battery_system_info
);
if
(
!
result
)
sbs
->
batteries_supported
=
battery_system_info
&
0x000f
;
return
result
;
}
static
int
acpi_battery_get_info
(
struct
acpi_battery
*
battery
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
s16
battery_mode
;
s16
specification_info
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x03
,
&
battery_mode
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
battery
->
info
.
capacity_mode
=
(
battery_mode
&
0x8000
)
>>
15
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x10
,
&
battery
->
info
.
full_charge_capacity
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x18
,
&
battery
->
info
.
design_capacity
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x19
,
&
battery
->
info
.
design_voltage
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x1a
,
&
specification_info
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
switch
((
specification_info
&
0x0f00
)
>>
8
)
{
case
1
:
battery
->
info
.
vscale
=
10
;
break
;
case
2
:
battery
->
info
.
vscale
=
100
;
break
;
case
3
:
battery
->
info
.
vscale
=
1000
;
break
;
default:
battery
->
info
.
vscale
=
1
;
}
switch
((
specification_info
&
0xf000
)
>>
12
)
{
case
1
:
battery
->
info
.
ipscale
=
10
;
break
;
case
2
:
battery
->
info
.
ipscale
=
100
;
break
;
case
3
:
battery
->
info
.
ipscale
=
1000
;
int
i
,
result
=
0
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
info_readers
);
++
i
)
{
result
=
acpi_smbus_read
(
battery
->
sbs
->
hc
,
info_readers
[
i
].
mode
,
ACPI_SBS_BATTERY
,
info_readers
[
i
].
command
,
(
u8
*
)
battery
+
info_readers
[
i
].
offset
);
if
(
result
)
break
;
default:
battery
->
info
.
ipscale
=
1
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x1c
,
&
battery
->
info
.
serial_number
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_str
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x20
,
battery
->
info
.
manufacturer_name
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_str() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_str
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x21
,
battery
->
info
.
device_name
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_str() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_str
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x22
,
battery
->
info
.
device_chemistry
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_str() failed"
));
goto
end
;
}
end:
return
result
;
}
static
int
acpi_battery_get_state
(
struct
acpi_battery
*
battery
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x09
,
&
battery
->
state
.
voltage
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x0a
,
&
battery
->
state
.
amperage
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x0f
,
&
battery
->
state
.
remaining_capacity
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
int
i
,
result
=
0
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x16
,
&
battery
->
state
.
battery_state
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
if
(
battery
->
update_time
&&
time_before
(
jiffies
,
battery
->
update_time
+
msecs_to_jiffies
(
cache_time
)))
return
0
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
state_readers
);
++
i
)
{
result
=
acpi_smbus_read
(
battery
->
sbs
->
hc
,
state_readers
[
i
].
mode
,
ACPI_SBS_BATTERY
,
state_readers
[
i
].
command
,
(
u8
*
)
battery
+
state_readers
[
i
].
offset
);
if
(
result
)
goto
end
;
}
end:
battery
->
update_time
=
jiffies
;
return
result
;
}
static
int
acpi_battery_get_alarm
(
struct
acpi_battery
*
battery
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x01
,
&
battery
->
alarm
.
remaining_capacity
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
end:
return
result
;
return
acpi_smbus_read
(
battery
->
sbs
->
hc
,
SMBUS_READ_WORD
,
ACPI_SBS_BATTERY
,
0x01
,
(
u8
*
)
&
battery
->
alarm_capacity
);
}
static
int
acpi_battery_set_alarm
(
struct
acpi_battery
*
battery
,
unsigned
long
alarm
)
static
int
acpi_battery_set_alarm
(
struct
acpi_battery
*
battery
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
s16
battery_mode
;
int
foo
;
u16
value
,
sel
=
1
<<
(
battery
->
id
+
12
);
result
=
acpi_battery_select
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_select() failed"
));
goto
end
;
}
int
ret
;
/* If necessary, enable the alarm */
if
(
alarm
>
0
)
{
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x03
,
&
battery_mode
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
if
(
sbs
->
manager_present
)
{
ret
=
acpi_smbus_read
(
sbs
->
hc
,
SMBUS_READ_WORD
,
ACPI_SBS_MANAGER
,
0x01
,
(
u8
*
)
&
value
);
if
(
ret
)
goto
end
;
}
result
=
acpi_sbs_write_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x01
,
battery_mode
&
0xbfff
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_write_word() failed"
));
if
((
value
&
0xf000
)
!=
sel
)
{
value
&=
0x0fff
;
value
|=
sel
;
ret
=
acpi_smbus_write
(
sbs
->
hc
,
SMBUS_WRITE_WORD
,
ACPI_SBS_MANAGER
,
0x01
,
(
u8
*
)
&
value
,
2
);
if
(
ret
)
goto
end
;
}
}
foo
=
alarm
/
(
battery
->
info
.
capacity_mode
?
10
:
1
);
result
=
acpi_sbs_write_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x01
,
foo
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_write_word() failed"
));
goto
end
;
}
ret
=
acpi_smbus_write
(
sbs
->
hc
,
SMBUS_WRITE_WORD
,
ACPI_SBS_BATTERY
,
0x01
,
(
u8
*
)
&
battery
->
alarm_capacity
,
2
);
end:
return
result
;
return
ret
;
}
static
int
acpi_
battery_set_mode
(
struct
acpi_battery
*
battery
)
static
int
acpi_
ac_get_present
(
struct
acpi_sbs
*
sbs
)
{
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
s16
battery_mode
;
if
(
capacity_mode
==
DEF_CAPACITY_UNIT
)
{
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x03
,
&
battery_mode
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
if
(
capacity_mode
==
MAH_CAPACITY_UNIT
)
{
battery_mode
&=
0x7fff
;
}
else
{
battery_mode
|=
0x8000
;
}
result
=
acpi_sbs_write_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x03
,
battery_mode
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_write_word() failed"
));
goto
end
;
}
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SB_SMBUS_ADDR
,
0x03
,
&
battery_mode
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
int
result
;
u16
status
;
end:
result
=
acpi_smbus_read
(
sbs
->
hc
,
SMBUS_READ_WORD
,
ACPI_SBS_CHARGER
,
0x13
,
(
u8
*
)
&
status
);
if
(
!
result
)
sbs
->
charger_present
=
(
status
>>
15
)
&
0x1
;
return
result
;
}
static
int
acpi_battery_init
(
struct
acpi_battery
*
battery
)
static
ssize_t
acpi_battery_alarm_show
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
{
int
result
=
0
;
result
=
acpi_battery_select
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_select() failed"
));
goto
end
;
}
result
=
acpi_battery_set_mode
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_set_mode() failed"
));
goto
end
;
}
result
=
acpi_battery_get_info
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_info() failed"
));
goto
end
;
}
result
=
acpi_battery_get_state
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_state() failed"
));
goto
end
;
}
result
=
acpi_battery_get_alarm
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_alarm() failed"
));
goto
end
;
}
end:
return
result
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
acpi_battery_get_alarm
(
battery
);
return
sprintf
(
buf
,
"%d
\n
"
,
battery
->
alarm_capacity
*
acpi_battery_scale
(
battery
)
*
1000
);
}
static
int
acpi_ac_get_present
(
struct
acpi_sbs
*
sbs
)
static
ssize_t
acpi_battery_alarm_store
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
int
result
=
0
;
s16
charger_status
;
result
=
acpi_sbs_read_word
(
sbs
,
ACPI_SBC_SMBUS_ADDR
,
0x13
,
&
charger_status
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_read_word() failed"
));
goto
end
;
}
sbs
->
ac
.
ac_present
=
(
charger_status
&
0x8000
)
>>
15
;
end:
return
result
;
unsigned
long
x
;
struct
acpi_battery
*
battery
=
to_acpi_battery
(
dev_get_drvdata
(
dev
));
if
(
sscanf
(
buf
,
"%ld
\n
"
,
&
x
)
==
1
)
battery
->
alarm_capacity
=
x
/
(
1000
*
acpi_battery_scale
(
battery
));
if
(
battery
->
present
)
acpi_battery_set_alarm
(
battery
);
return
count
;
}
static
struct
device_attribute
alarm_attr
=
{
.
attr
=
{.
name
=
"alarm"
,
.
mode
=
0644
,
.
owner
=
THIS_MODULE
},
.
show
=
acpi_battery_alarm_show
,
.
store
=
acpi_battery_alarm_store
,
};
/* --------------------------------------------------------------------------
FS Interface (/proc/acpi)
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCFS
/* Generic Routines */
static
int
acpi_sbs_
generic_
add_fs
(
struct
proc_dir_entry
**
dir
,
acpi_sbs_add_fs
(
struct
proc_dir_entry
**
dir
,
struct
proc_dir_entry
*
parent_dir
,
char
*
dir_name
,
struct
file_operations
*
info_fops
,
...
...
@@ -872,8 +483,6 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if
(
!*
dir
)
{
*
dir
=
proc_mkdir
(
dir_name
,
parent_dir
);
if
(
!*
dir
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"proc_mkdir() failed"
));
return
-
ENODEV
;
}
(
*
dir
)
->
owner
=
THIS_MODULE
;
...
...
@@ -882,10 +491,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'info' [R] */
if
(
info_fops
)
{
entry
=
create_proc_entry
(
ACPI_SBS_FILE_INFO
,
S_IRUGO
,
*
dir
);
if
(
!
entry
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"create_proc_entry() failed"
));
}
else
{
if
(
entry
)
{
entry
->
proc_fops
=
info_fops
;
entry
->
data
=
data
;
entry
->
owner
=
THIS_MODULE
;
...
...
@@ -895,10 +501,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'state' [R] */
if
(
state_fops
)
{
entry
=
create_proc_entry
(
ACPI_SBS_FILE_STATE
,
S_IRUGO
,
*
dir
);
if
(
!
entry
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"create_proc_entry() failed"
));
}
else
{
if
(
entry
)
{
entry
->
proc_fops
=
state_fops
;
entry
->
data
=
data
;
entry
->
owner
=
THIS_MODULE
;
...
...
@@ -908,24 +511,19 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'alarm' [R/W] */
if
(
alarm_fops
)
{
entry
=
create_proc_entry
(
ACPI_SBS_FILE_ALARM
,
S_IRUGO
,
*
dir
);
if
(
!
entry
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"create_proc_entry() failed"
));
}
else
{
if
(
entry
)
{
entry
->
proc_fops
=
alarm_fops
;
entry
->
data
=
data
;
entry
->
owner
=
THIS_MODULE
;
}
}
return
0
;
}
static
void
acpi_sbs_
generic_
remove_fs
(
struct
proc_dir_entry
**
dir
,
acpi_sbs_remove_fs
(
struct
proc_dir_entry
**
dir
,
struct
proc_dir_entry
*
parent_dir
)
{
if
(
*
dir
)
{
remove_proc_entry
(
ACPI_SBS_FILE_INFO
,
*
dir
);
remove_proc_entry
(
ACPI_SBS_FILE_STATE
,
*
dir
);
...
...
@@ -933,82 +531,52 @@ acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
remove_proc_entry
((
*
dir
)
->
name
,
parent_dir
);
*
dir
=
NULL
;
}
}
/* Smart Battery Interface */
static
struct
proc_dir_entry
*
acpi_battery_dir
=
NULL
;
static
inline
char
*
acpi_battery_units
(
struct
acpi_battery
*
battery
)
{
return
acpi_battery_mode
(
battery
)
?
" mWh"
:
" mAh"
;
}
static
int
acpi_battery_read_info
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
cscale
;
int
result
=
0
;
if
(
sbs_mutex_lock
(
sbs
))
{
return
-
ENODEV
;
}
mutex_lock
(
&
sbs
->
lock
);
result
=
acpi_check_update_proc
(
sbs
);
if
(
result
)
goto
end
;
if
(
update_time
==
0
)
{
result
=
acpi_sbs_update_run
(
sbs
,
battery
->
id
,
DATA_TYPE_INFO
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_update_run() failed"
));
}
}
if
(
battery
->
battery_present
)
{
seq_printf
(
seq
,
"present: yes
\n
"
);
}
else
{
seq_printf
(
seq
,
"present: no
\n
"
);
seq_printf
(
seq
,
"present: %s
\n
"
,
(
battery
->
present
)
?
"yes"
:
"no"
);
if
(
!
battery
->
present
)
goto
end
;
}
if
(
battery
->
info
.
capacity_mode
)
{
cscale
=
battery
->
info
.
vscale
*
battery
->
info
.
ipscale
;
}
else
{
cscale
=
battery
->
info
.
ipscale
;
}
seq_printf
(
seq
,
"design capacity: %i%s
\n
"
,
battery
->
info
.
design_capacity
*
cscale
,
battery
->
info
.
capacity_mode
?
"0 mWh"
:
" mAh"
);
battery
->
design_capacity
*
acpi_battery_scale
(
battery
),
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"last full capacity: %i%s
\n
"
,
battery
->
info
.
full_charge_capacity
*
cscale
,
battery
->
info
.
capacity_mode
?
"0 mWh"
:
" mAh"
);
battery
->
full_charge_capacity
*
acpi_battery_scale
(
battery
),
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"battery technology: rechargeable
\n
"
);
seq_printf
(
seq
,
"design voltage: %i mV
\n
"
,
battery
->
info
.
design_voltage
*
battery
->
info
.
vscale
);
battery
->
design_voltage
*
acpi_battery_vscale
(
battery
));
seq_printf
(
seq
,
"design capacity warning: unknown
\n
"
);
seq_printf
(
seq
,
"design capacity low: unknown
\n
"
);
seq_printf
(
seq
,
"capacity granularity 1: unknown
\n
"
);
seq_printf
(
seq
,
"capacity granularity 2: unknown
\n
"
);
seq_printf
(
seq
,
"model number: %s
\n
"
,
battery
->
info
.
device_name
);
seq_printf
(
seq
,
"model number: %s
\n
"
,
battery
->
device_name
);
seq_printf
(
seq
,
"serial number: %i
\n
"
,
battery
->
info
.
serial_number
);
battery
->
serial_number
);
seq_printf
(
seq
,
"battery type: %s
\n
"
,
battery
->
info
.
device_chemistry
);
battery
->
device_chemistry
);
seq_printf
(
seq
,
"OEM info: %s
\n
"
,
battery
->
info
.
manufacturer_name
);
battery
->
manufacturer_name
);
end:
sbs_mutex_unlock
(
sbs
);
mutex_unlock
(
&
sbs
->
lock
);
return
result
;
}
...
...
@@ -1017,78 +585,34 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
return
single_open
(
file
,
acpi_battery_read_info
,
PDE
(
inode
)
->
data
);
}
static
int
acpi_battery_read_state
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
int
cscale
;
int
foo
;
if
(
sbs_mutex_lock
(
sbs
))
{
return
-
ENODEV
;
}
result
=
acpi_check_update_proc
(
sbs
);
if
(
result
)
goto
end
;
if
(
update_time
==
0
)
{
result
=
acpi_sbs_update_run
(
sbs
,
battery
->
id
,
DATA_TYPE_STATE
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_update_run() failed"
));
}
}
if
(
battery
->
battery_present
)
{
seq_printf
(
seq
,
"present: yes
\n
"
);
}
else
{
seq_printf
(
seq
,
"present: no
\n
"
);
goto
end
;
}
if
(
battery
->
info
.
capacity_mode
)
{
cscale
=
battery
->
info
.
vscale
*
battery
->
info
.
ipscale
;
}
else
{
cscale
=
battery
->
info
.
ipscale
;
}
if
(
battery
->
state
.
battery_state
&
0x0010
)
{
seq_printf
(
seq
,
"capacity state: critical
\n
"
);
}
else
{
seq_printf
(
seq
,
"capacity state: ok
\n
"
);
}
static
int
acpi_battery_read_state
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
foo
=
(
s16
)
battery
->
state
.
amperage
*
battery
->
info
.
ipscale
;
if
(
battery
->
info
.
capacity_mode
)
{
foo
=
foo
*
battery
->
info
.
design_voltage
/
1000
;
}
if
(
battery
->
state
.
amperage
<
0
)
{
seq_printf
(
seq
,
"charging state: discharging
\n
"
);
seq_printf
(
seq
,
"present rate: %d %s
\n
"
,
-
foo
,
battery
->
info
.
capacity_mode
?
"mW"
:
"mA"
);
}
else
if
(
battery
->
state
.
amperage
>
0
)
{
seq_printf
(
seq
,
"charging state: charging
\n
"
);
seq_printf
(
seq
,
"present rate: %d %s
\n
"
,
foo
,
battery
->
info
.
capacity_mode
?
"mW"
:
"mA"
);
}
else
{
seq_printf
(
seq
,
"charging state: charged
\n
"
);
seq_printf
(
seq
,
"present rate: 0 %s
\n
"
,
battery
->
info
.
capacity_mode
?
"mW"
:
"mA"
);
}
mutex_lock
(
&
sbs
->
lock
);
seq_printf
(
seq
,
"present: %s
\n
"
,
(
battery
->
present
)
?
"yes"
:
"no"
);
if
(
!
battery
->
present
)
goto
end
;
acpi_battery_get_state
(
battery
);
seq_printf
(
seq
,
"capacity state: %s
\n
"
,
(
battery
->
state
&
0x0010
)
?
"critical"
:
"ok"
);
seq_printf
(
seq
,
"charging state: %s
\n
"
,
(
battery
->
current_now
<
0
)
?
"discharging"
:
((
battery
->
current_now
>
0
)
?
"charging"
:
"charged"
));
seq_printf
(
seq
,
"present rate: %d mA
\n
"
,
abs
(
battery
->
current_now
)
*
acpi_battery_ipscale
(
battery
));
seq_printf
(
seq
,
"remaining capacity: %i%s
\n
"
,
battery
->
state
.
remaining_capacity
*
cscale
,
battery
->
info
.
capacity_mode
?
"0 mWh"
:
" mAh"
);
battery
->
capacity_now
*
acpi_battery_scale
(
battery
),
acpi_battery_units
(
battery
));
seq_printf
(
seq
,
"present voltage: %i mV
\n
"
,
battery
->
state
.
voltage
*
battery
->
info
.
vscale
);
battery
->
voltage_now
*
acpi_battery_vscale
(
battery
)
);
end:
sbs_mutex_unlock
(
sbs
);
mutex_unlock
(
&
sbs
->
lock
);
return
result
;
}
...
...
@@ -1102,48 +626,25 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
int
result
=
0
;
int
cscale
;
if
(
sbs_mutex_lock
(
sbs
))
{
return
-
ENODEV
;
}
result
=
acpi_check_update_proc
(
sbs
);
if
(
result
)
goto
end
;
if
(
update_time
==
0
)
{
result
=
acpi_sbs_update_run
(
sbs
,
battery
->
id
,
DATA_TYPE_ALARM
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_update_run() failed"
));
}
}
mutex_lock
(
&
sbs
->
lock
);
if
(
!
battery
->
battery_
present
)
{
if
(
!
battery
->
present
)
{
seq_printf
(
seq
,
"present: no
\n
"
);
goto
end
;
}
if
(
battery
->
info
.
capacity_mode
)
{
cscale
=
battery
->
info
.
vscale
*
battery
->
info
.
ipscale
;
}
else
{
cscale
=
battery
->
info
.
ipscale
;
}
acpi_battery_get_alarm
(
battery
);
seq_printf
(
seq
,
"alarm: "
);
if
(
battery
->
alarm
.
remaining_capacity
)
{
if
(
battery
->
alarm
_capacity
)
seq_printf
(
seq
,
"%i%s
\n
"
,
battery
->
alarm
.
remaining_capacity
*
cscale
,
battery
->
info
.
capacity_mode
?
"0 mWh"
:
" mAh"
);
}
else
{
battery
->
alarm_capacity
*
acpi_battery_scale
(
battery
),
acpi_battery_units
(
battery
));
else
seq_printf
(
seq
,
"disabled
\n
"
);
}
end:
sbs_mutex_unlock
(
sbs
);
mutex_unlock
(
&
sbs
->
lock
);
return
result
;
}
...
...
@@ -1155,59 +656,29 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
struct
acpi_battery
*
battery
=
seq
->
private
;
struct
acpi_sbs
*
sbs
=
battery
->
sbs
;
char
alarm_string
[
12
]
=
{
'\0'
};
int
result
,
old_alarm
,
new_alarm
;
if
(
sbs_mutex_lock
(
sbs
))
{
return
-
ENODEV
;
}
result
=
acpi_check_update_proc
(
sbs
);
if
(
result
)
goto
end
;
if
(
!
battery
->
battery_present
)
{
int
result
=
0
;
mutex_lock
(
&
sbs
->
lock
);
if
(
!
battery
->
present
)
{
result
=
-
ENODEV
;
goto
end
;
}
if
(
count
>
sizeof
(
alarm_string
)
-
1
)
{
result
=
-
EINVAL
;
goto
end
;
}
if
(
copy_from_user
(
alarm_string
,
buffer
,
count
))
{
result
=
-
EFAULT
;
goto
end
;
}
alarm_string
[
count
]
=
0
;
old_alarm
=
battery
->
alarm
.
remaining_capacity
;
new_alarm
=
simple_strtoul
(
alarm_string
,
NULL
,
0
);
result
=
acpi_battery_set_alarm
(
battery
,
new_alarm
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_set_alarm() failed"
));
acpi_battery_set_alarm
(
battery
,
old_alarm
);
goto
end
;
}
result
=
acpi_battery_get_alarm
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_alarm() failed"
));
acpi_battery_set_alarm
(
battery
,
old_alarm
);
goto
end
;
}
battery
->
alarm_capacity
=
simple_strtoul
(
alarm_string
,
NULL
,
0
)
/
acpi_battery_scale
(
battery
);
acpi_battery_set_alarm
(
battery
);
end:
sbs_mutex_unlock
(
sbs
);
if
(
result
)
{
mutex_unlock
(
&
sbs
->
lock
);
if
(
result
)
return
result
;
}
else
{
return
count
;
}
}
static
int
acpi_battery_alarm_open_fs
(
struct
inode
*
inode
,
struct
file
*
file
)
...
...
@@ -1246,26 +717,15 @@ static struct proc_dir_entry *acpi_ac_dir = NULL;
static
int
acpi_ac_read_state
(
struct
seq_file
*
seq
,
void
*
offset
)
{
struct
acpi_sbs
*
sbs
=
seq
->
private
;
int
result
;
if
(
sbs_mutex_lock
(
sbs
))
{
return
-
ENODEV
;
}
struct
acpi_sbs
*
sbs
=
seq
->
private
;
if
(
update_time
==
0
)
{
result
=
acpi_sbs_update_run
(
sbs
,
-
1
,
DATA_TYPE_AC_STATE
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_update_run() failed"
));
}
}
mutex_lock
(
&
sbs
->
lock
);
seq_printf
(
seq
,
"state: %s
\n
"
,
sbs
->
ac
.
ac_present
?
"on-line"
:
"off-line"
);
sbs_mutex_unlock
(
sbs
);
sbs
->
charger_present
?
"on-line"
:
"off-line"
);
mutex_unlock
(
&
sbs
->
lock
);
return
0
;
}
...
...
@@ -1282,429 +742,203 @@ static struct file_operations acpi_ac_state_fops = {
.
owner
=
THIS_MODULE
,
};
#endif
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static
int
acpi_battery_read
(
struct
acpi_battery
*
battery
)
{
int
result
=
0
,
saved_present
=
battery
->
present
;
u16
state
;
if
(
battery
->
sbs
->
manager_present
)
{
result
=
acpi_smbus_read
(
battery
->
sbs
->
hc
,
SMBUS_READ_WORD
,
ACPI_SBS_MANAGER
,
0x01
,
(
u8
*
)
&
state
);
if
(
!
result
)
battery
->
present
=
state
&
(
1
<<
battery
->
id
);
state
&=
0x0fff
;
state
|=
1
<<
(
battery
->
id
+
12
);
acpi_smbus_write
(
battery
->
sbs
->
hc
,
SMBUS_WRITE_WORD
,
ACPI_SBS_MANAGER
,
0x01
,
(
u8
*
)
&
state
,
2
);
}
else
if
(
battery
->
id
==
0
)
battery
->
present
=
1
;
if
(
result
||
!
battery
->
present
)
return
result
;
/* Smart Battery */
if
(
saved_present
!=
battery
->
present
)
{
battery
->
update_time
=
0
;
result
=
acpi_battery_get_info
(
battery
);
if
(
result
)
return
result
;
}
result
=
acpi_battery_get_state
(
battery
);
return
result
;
}
/* Smart Battery */
static
int
acpi_battery_add
(
struct
acpi_sbs
*
sbs
,
int
id
)
{
int
is_present
;
struct
acpi_battery
*
battery
=
&
sbs
->
battery
[
id
]
;
int
result
;
char
dir_name
[
32
];
struct
acpi_battery
*
battery
;
battery
=
&
sbs
->
battery
[
id
];
battery
->
alive
=
0
;
battery
->
init_state
=
0
;
battery
->
id
=
id
;
battery
->
sbs
=
sbs
;
result
=
acpi_battery_read
(
battery
);
if
(
result
)
return
result
;
result
=
acpi_battery_select
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_select() failed"
));
goto
end
;
}
result
=
acpi_battery_get_present
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_present() failed"
));
goto
end
;
}
is_present
=
battery
->
battery_present
;
if
(
is_present
)
{
result
=
acpi_battery_init
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_init() failed"
));
goto
end
;
}
battery
->
init_state
=
1
;
}
sprintf
(
dir_name
,
ACPI_BATTERY_DIR_NAME
,
id
);
result
=
acpi_sbs_generic_add_fs
(
&
battery
->
battery_entry
,
acpi_battery_dir
,
dir_name
,
&
acpi_battery_info_fops
,
&
acpi_battery_state_fops
,
&
acpi_battery_alarm_fops
,
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_generic_add_fs() failed"
));
goto
end
;
sprintf
(
battery
->
name
,
ACPI_BATTERY_DIR_NAME
,
id
);
#ifdef CONFIG_ACPI_PROCFS
acpi_sbs_add_fs
(
&
battery
->
proc_entry
,
acpi_battery_dir
,
battery
->
name
,
&
acpi_battery_info_fops
,
&
acpi_battery_state_fops
,
&
acpi_battery_alarm_fops
,
battery
);
#endif
battery
->
bat
.
name
=
battery
->
name
;
battery
->
bat
.
type
=
POWER_SUPPLY_TYPE_BATTERY
;
if
(
!
acpi_battery_mode
(
battery
))
{
battery
->
bat
.
properties
=
sbs_charge_battery_props
;
battery
->
bat
.
num_properties
=
ARRAY_SIZE
(
sbs_charge_battery_props
);
}
else
{
battery
->
bat
.
properties
=
sbs_energy_battery_props
;
battery
->
bat
.
num_properties
=
ARRAY_SIZE
(
sbs_energy_battery_props
);
}
battery
->
alive
=
1
;
battery
->
bat
.
get_property
=
acpi_sbs_battery_get_property
;
result
=
power_supply_register
(
&
sbs
->
device
->
dev
,
&
battery
->
bat
);
device_create_file
(
battery
->
bat
.
dev
,
&
alarm_attr
);
printk
(
KERN_INFO
PREFIX
"%s [%s]: Battery Slot [%s] (battery %s)
\n
"
,
ACPI_SBS_DEVICE_NAME
,
acpi_device_bid
(
sbs
->
device
),
dir_name
,
sbs
->
battery
->
battery_present
?
"present"
:
"absent"
);
end:
ACPI_SBS_DEVICE_NAME
,
acpi_device_bid
(
sbs
->
device
),
battery
->
name
,
sbs
->
battery
->
present
?
"present"
:
"absent"
);
return
result
;
}
static
void
acpi_battery_remove
(
struct
acpi_sbs
*
sbs
,
int
id
)
{
if
(
sbs
->
battery
[
id
].
battery_entry
)
{
acpi_sbs_generic_remove_fs
(
&
(
sbs
->
battery
[
id
].
battery_entry
),
if
(
sbs
->
battery
[
id
].
bat
.
dev
)
device_remove_file
(
sbs
->
battery
[
id
].
bat
.
dev
,
&
alarm_attr
);
power_supply_unregister
(
&
sbs
->
battery
[
id
].
bat
);
#ifdef CONFIG_ACPI_PROCFS
if
(
sbs
->
battery
[
id
].
proc_entry
)
{
acpi_sbs_remove_fs
(
&
(
sbs
->
battery
[
id
].
proc_entry
),
acpi_battery_dir
);
}
#endif
}
static
int
acpi_
ac
_add
(
struct
acpi_sbs
*
sbs
)
static
int
acpi_
charger
_add
(
struct
acpi_sbs
*
sbs
)
{
int
result
;
result
=
acpi_ac_get_present
(
sbs
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ac_get_present() failed"
));
if
(
result
)
goto
end
;
}
result
=
acpi_sbs_generic_add_fs
(
&
sbs
->
ac_entry
,
acpi_ac_dir
,
ACPI_AC_DIR_NAME
,
NULL
,
&
acpi_ac_state_fops
,
NULL
,
sbs
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_generic_add_fs() failed"
));
#ifdef CONFIG_ACPI_PROCFS
result
=
acpi_sbs_add_fs
(
&
sbs
->
charger_entry
,
acpi_ac_dir
,
ACPI_AC_DIR_NAME
,
NULL
,
&
acpi_ac_state_fops
,
NULL
,
sbs
);
if
(
result
)
goto
end
;
}
#endif
sbs
->
charger
.
name
=
"sbs-charger"
;
sbs
->
charger
.
type
=
POWER_SUPPLY_TYPE_MAINS
;
sbs
->
charger
.
properties
=
sbs_ac_props
;
sbs
->
charger
.
num_properties
=
ARRAY_SIZE
(
sbs_ac_props
);
sbs
->
charger
.
get_property
=
sbs_get_ac_property
;
power_supply_register
(
&
sbs
->
device
->
dev
,
&
sbs
->
charger
);
printk
(
KERN_INFO
PREFIX
"%s [%s]: AC Adapter [%s] (%s)
\n
"
,
ACPI_SBS_DEVICE_NAME
,
acpi_device_bid
(
sbs
->
device
),
ACPI_AC_DIR_NAME
,
sbs
->
ac
.
ac_present
?
"on-line"
:
"off-line"
);
ACPI_AC_DIR_NAME
,
sbs
->
charger_present
?
"on-line"
:
"off-line"
);
end:
return
result
;
}
static
void
acpi_ac_remove
(
struct
acpi_sbs
*
sbs
)
{
if
(
sbs
->
ac_entry
)
{
acpi_sbs_generic_remove_fs
(
&
sbs
->
ac_entry
,
acpi_ac_dir
);
}
}
static
void
acpi_sbs_update_time_run
(
unsigned
long
data
)
static
void
acpi_charger_remove
(
struct
acpi_sbs
*
sbs
)
{
acpi_os_execute
(
OSL_GPE_HANDLER
,
acpi_sbs_update_time
,
(
void
*
)
data
);
if
(
sbs
->
charger
.
dev
)
power_supply_unregister
(
&
sbs
->
charger
);
#ifdef CONFIG_ACPI_PROCFS
if
(
sbs
->
charger_entry
)
acpi_sbs_remove_fs
(
&
sbs
->
charger_entry
,
acpi_ac_dir
);
#endif
}
static
int
acpi_sbs_update_run
(
struct
acpi_sbs
*
sbs
,
int
id
,
int
data_type
)
void
acpi_sbs_callback
(
void
*
context
)
{
struct
acpi_battery
*
battery
;
int
result
=
0
,
cnt
;
int
old_ac_present
=
-
1
;
int
old_battery_present
=
-
1
;
int
new_ac_present
=
-
1
;
int
new_battery_present
=
-
1
;
int
id_min
=
0
,
id_max
=
MAX_SBS_BAT
-
1
;
char
dir_name
[
32
];
int
do_battery_init
=
0
,
do_ac_init
=
0
;
int
old_remaining_capacity
=
0
;
int
update_battery
=
1
;
int
up_tm
=
update_time
;
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
if
(
id
>=
0
)
{
id_min
=
id_max
=
id
;
}
if
(
data_type
==
DATA_TYPE_COMMON
&&
up_tm
>
0
)
{
cnt
=
up_tm
/
(
up_tm
>
UPDATE_DELAY
?
UPDATE_DELAY
:
up_tm
);
if
(
sbs
->
run_cnt
%
cnt
!=
0
)
{
update_battery
=
0
;
}
}
sbs
->
run_cnt
++
;
old_ac_present
=
sbs
->
ac
.
ac_present
;
result
=
acpi_ac_get_present
(
sbs
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ac_get_present() failed"
));
}
new_ac_present
=
sbs
->
ac
.
ac_present
;
do_ac_init
=
(
old_ac_present
!=
new_ac_present
);
if
(
sbs
->
run_cnt
==
1
&&
data_type
==
DATA_TYPE_COMMON
)
{
do_ac_init
=
1
;
}
if
(
do_ac_init
)
{
result
=
acpi_sbs_generate_event
(
sbs
->
device
,
ACPI_SBS_AC_NOTIFY_STATUS
,
new_ac_present
,
ACPI_AC_DIR_NAME
,
ACPI_AC_CLASS
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_generate_event() failed"
));
}
}
if
(
data_type
==
DATA_TYPE_COMMON
)
{
if
(
!
do_ac_init
&&
!
update_battery
)
{
goto
end
;
}
}
if
(
data_type
==
DATA_TYPE_AC_STATE
&&
!
do_ac_init
)
{
goto
end
;
}
for
(
id
=
id_min
;
id
<=
id_max
;
id
++
)
{
battery
=
&
sbs
->
battery
[
id
];
if
(
battery
->
alive
==
0
)
{
continue
;
}
old_remaining_capacity
=
battery
->
state
.
remaining_capacity
;
old_battery_present
=
battery
->
battery_present
;
result
=
acpi_battery_select
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_select() failed"
));
}
result
=
acpi_battery_get_present
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_present() failed"
));
}
new_battery_present
=
battery
->
battery_present
;
do_battery_init
=
((
old_battery_present
!=
new_battery_present
)
&&
new_battery_present
);
if
(
!
new_battery_present
)
goto
event
;
if
(
do_ac_init
||
do_battery_init
)
{
result
=
acpi_battery_init
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_init() "
"failed"
));
}
}
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
if
((
data_type
==
DATA_TYPE_COMMON
||
data_type
==
DATA_TYPE_INFO
)
&&
new_battery_present
)
{
result
=
acpi_battery_get_info
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_info() failed"
));
}
}
if
(
data_type
==
DATA_TYPE_INFO
)
{
int
id
;
struct
acpi_sbs
*
sbs
=
context
;
struct
acpi_battery
*
bat
;
u8
saved_charger_state
=
sbs
->
charger_present
;
u8
saved_battery_state
;
acpi_ac_get_present
(
sbs
);
if
(
sbs
->
charger_present
!=
saved_charger_state
)
{
#ifdef CONFIG_ACPI_PROC_EVENT
acpi_bus_generate_proc_event4
(
ACPI_AC_CLASS
,
ACPI_AC_DIR_NAME
,
ACPI_SBS_NOTIFY_STATUS
,
sbs
->
charger_present
);
#endif
kobject_uevent
(
&
sbs
->
charger
.
dev
->
kobj
,
KOBJ_CHANGE
);
}
if
(
sbs
->
manager_present
)
{
for
(
id
=
0
;
id
<
MAX_SBS_BAT
;
++
id
)
{
if
(
!
(
sbs
->
batteries_supported
&
(
1
<<
id
)))
continue
;
}
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
if
((
data_type
==
DATA_TYPE_COMMON
||
data_type
==
DATA_TYPE_STATE
)
&&
new_battery_present
)
{
result
=
acpi_battery_get_state
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_state() failed"
));
}
}
if
(
data_type
==
DATA_TYPE_STATE
)
{
goto
event
;
}
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
if
((
data_type
==
DATA_TYPE_COMMON
||
data_type
==
DATA_TYPE_ALARM
)
&&
new_battery_present
)
{
result
=
acpi_battery_get_alarm
(
battery
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_get_alarm() "
"failed"
));
}
}
if
(
data_type
==
DATA_TYPE_ALARM
)
{
bat
=
&
sbs
->
battery
[
id
];
saved_battery_state
=
bat
->
present
;
acpi_battery_read
(
bat
);
if
(
saved_battery_state
==
bat
->
present
)
continue
;
}
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
event:
if
(
old_battery_present
!=
new_battery_present
||
do_ac_init
||
old_remaining_capacity
!=
battery
->
state
.
remaining_capacity
)
{
sprintf
(
dir_name
,
ACPI_BATTERY_DIR_NAME
,
id
);
result
=
acpi_sbs_generate_event
(
sbs
->
device
,
ACPI_SBS_BATTERY_NOTIFY_STATUS
,
new_battery_present
,
dir_name
,
ACPI_BATTERY_CLASS
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_generate_event() "
"failed"
));
#ifdef CONFIG_ACPI_PROC_EVENT
acpi_bus_generate_proc_event4
(
ACPI_BATTERY_CLASS
,
bat
->
name
,
ACPI_SBS_NOTIFY_STATUS
,
bat
->
present
);
#endif
kobject_uevent
(
&
bat
->
bat
.
dev
->
kobj
,
KOBJ_CHANGE
);
}
}
}
end:
return
result
;
}
static
void
acpi_sbs_update_time
(
void
*
data
)
{
struct
acpi_sbs
*
sbs
=
data
;
unsigned
long
delay
=
-
1
;
int
result
;
unsigned
int
up_tm
=
update_time
;
if
(
sbs_mutex_lock
(
sbs
))
return
;
result
=
acpi_sbs_update_run
(
sbs
,
-
1
,
DATA_TYPE_COMMON
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_update_run() failed"
));
}
if
(
sbs_zombie
(
sbs
))
{
goto
end
;
}
if
(
!
up_tm
)
{
if
(
timer_pending
(
&
sbs
->
update_timer
))
del_timer
(
&
sbs
->
update_timer
);
}
else
{
delay
=
(
up_tm
>
UPDATE_DELAY
?
UPDATE_DELAY
:
up_tm
);
delay
=
jiffies
+
HZ
*
delay
;
if
(
timer_pending
(
&
sbs
->
update_timer
))
{
mod_timer
(
&
sbs
->
update_timer
,
delay
);
}
else
{
sbs
->
update_timer
.
data
=
(
unsigned
long
)
data
;
sbs
->
update_timer
.
function
=
acpi_sbs_update_time_run
;
sbs
->
update_timer
.
expires
=
delay
;
add_timer
(
&
sbs
->
update_timer
);
}
}
end:
sbs_mutex_unlock
(
sbs
);
}
static
int
acpi_sbs_remove
(
struct
acpi_device
*
device
,
int
type
);
static
int
acpi_sbs_add
(
struct
acpi_device
*
device
)
{
struct
acpi_sbs
*
sbs
=
NULL
;
int
result
=
0
,
remove_result
=
0
;
struct
acpi_sbs
*
sbs
;
int
result
=
0
;
int
id
;
acpi_status
status
=
AE_OK
;
unsigned
long
val
;
status
=
acpi_evaluate_integer
(
device
->
handle
,
"_EC"
,
NULL
,
&
val
);
if
(
ACPI_FAILURE
(
status
))
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"Error obtaining _EC"
));
return
-
EIO
;
}
sbs
=
kzalloc
(
sizeof
(
struct
acpi_sbs
),
GFP_KERNEL
);
if
(
!
sbs
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"kzalloc() failed"
));
result
=
-
ENOMEM
;
goto
end
;
}
mutex_init
(
&
sbs
->
mutex
);
sbs_mutex_lock
(
sbs
);
mutex_init
(
&
sbs
->
lock
);
sbs
->
base
=
0xff
&
(
val
>>
8
);
sbs
->
hc
=
acpi_driver_data
(
device
->
parent
);
sbs
->
device
=
device
;
strcpy
(
acpi_device_name
(
device
),
ACPI_SBS_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ACPI_SBS_CLASS
);
acpi_driver_data
(
device
)
=
sbs
;
result
=
acpi_ac_add
(
sbs
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_ac_add() failed"
));
goto
end
;
}
acpi_sbsm_get_info
(
sbs
);
if
(
!
sbs
->
sbsm_present
)
{
result
=
acpi_battery_add
(
sbs
,
0
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_add() failed"
));
goto
end
;
}
}
else
{
for
(
id
=
0
;
id
<
MAX_SBS_BAT
;
id
++
)
{
if
((
sbs
->
sbsm_batteries_supported
&
(
1
<<
id
)))
{
result
=
acpi_battery_add
(
sbs
,
id
);
if
(
result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_battery_add() failed"
));
goto
end
;
}
}
}
}
init_timer
(
&
sbs
->
update_timer
);
result
=
acpi_check_update_proc
(
sbs
);
result
=
acpi_charger_add
(
sbs
);
if
(
result
)
goto
end
;
result
=
acpi_manager_get_info
(
sbs
);
if
(
!
result
)
{
sbs
->
manager_present
=
1
;
for
(
id
=
0
;
id
<
MAX_SBS_BAT
;
++
id
)
if
((
sbs
->
batteries_supported
&
(
1
<<
id
)))
acpi_battery_add
(
sbs
,
id
);
}
else
acpi_battery_add
(
sbs
,
0
);
acpi_smbus_register_callback
(
sbs
->
hc
,
acpi_sbs_callback
,
sbs
);
end:
sbs_mutex_unlock
(
sbs
);
if
(
result
)
{
remove_result
=
acpi_sbs_remove
(
device
,
0
);
if
(
remove_result
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_sbs_remove() failed"
));
}
}
if
(
result
)
acpi_sbs_remove
(
device
,
0
);
return
result
;
}
...
...
@@ -1713,39 +947,25 @@ static int acpi_sbs_remove(struct acpi_device *device, int type)
struct
acpi_sbs
*
sbs
;
int
id
;
if
(
!
device
)
{
if
(
!
device
)
return
-
EINVAL
;
}
sbs
=
acpi_driver_data
(
device
);
if
(
!
sbs
)
{
if
(
!
sbs
)
return
-
EINVAL
;
}
sbs_mutex_lock
(
sbs
);
sbs
->
zombie
=
1
;
del_timer_sync
(
&
sbs
->
update_timer
);
acpi_os_wait_events_complete
(
NULL
);
del_timer_sync
(
&
sbs
->
update_timer
);
for
(
id
=
0
;
id
<
MAX_SBS_BAT
;
id
++
)
{
mutex_lock
(
&
sbs
->
lock
);
acpi_smbus_unregister_callback
(
sbs
->
hc
);
for
(
id
=
0
;
id
<
MAX_SBS_BAT
;
++
id
)
acpi_battery_remove
(
sbs
,
id
);
}
acpi_ac_remove
(
sbs
);
sbs_mutex_unlock
(
sbs
);
mutex_destroy
(
&
sbs
->
mutex
);
acpi_charger_remove
(
sbs
);
mutex_unlock
(
&
sbs
->
lock
);
mutex_destroy
(
&
sbs
->
lock
);
kfree
(
sbs
);
return
0
;
}
static
void
acpi_sbs_rmdirs
(
void
)
{
#ifdef CONFIG_ACPI_PROCFS
if
(
acpi_ac_dir
)
{
acpi_unlock_ac_dir
(
acpi_ac_dir
);
acpi_ac_dir
=
NULL
;
...
...
@@ -1754,69 +974,58 @@ static void acpi_sbs_rmdirs(void)
acpi_unlock_battery_dir
(
acpi_battery_dir
);
acpi_battery_dir
=
NULL
;
}
#endif
}
static
int
acpi_sbs_resume
(
struct
acpi_device
*
device
)
{
struct
acpi_sbs
*
sbs
;
if
(
!
device
)
return
-
EINVAL
;
sbs
=
device
->
driver_data
;
sbs
->
run_cnt
=
0
;
acpi_sbs_callback
(
sbs
);
return
0
;
}
static
struct
acpi_driver
acpi_sbs_driver
=
{
.
name
=
"sbs"
,
.
class
=
ACPI_SBS_CLASS
,
.
ids
=
sbs_device_ids
,
.
ops
=
{
.
add
=
acpi_sbs_add
,
.
remove
=
acpi_sbs_remove
,
.
resume
=
acpi_sbs_resume
,
},
};
static
int
__init
acpi_sbs_init
(
void
)
{
int
result
=
0
;
if
(
acpi_disabled
)
return
-
ENODEV
;
if
(
capacity_mode
!=
DEF_CAPACITY_UNIT
&&
capacity_mode
!=
MAH_CAPACITY_UNIT
&&
capacity_mode
!=
MWH_CAPACITY_UNIT
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"invalid capacity_mode = %d"
,
capacity_mode
));
return
-
EINVAL
;
}
#ifdef CONFIG_ACPI_PROCFS
acpi_ac_dir
=
acpi_lock_ac_dir
();
if
(
!
acpi_ac_dir
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_lock_ac_dir() failed"
));
if
(
!
acpi_ac_dir
)
return
-
ENODEV
;
}
acpi_battery_dir
=
acpi_lock_battery_dir
();
if
(
!
acpi_battery_dir
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_lock_battery_dir() failed"
));
acpi_sbs_rmdirs
();
return
-
ENODEV
;
}
#endif
result
=
acpi_bus_register_driver
(
&
acpi_sbs_driver
);
if
(
result
<
0
)
{
ACPI_EXCEPTION
((
AE_INFO
,
AE_ERROR
,
"acpi_bus_register_driver() failed"
));
acpi_sbs_rmdirs
();
return
-
ENODEV
;
}
return
0
;
}
static
void
__exit
acpi_sbs_exit
(
void
)
{
acpi_bus_unregister_driver
(
&
acpi_sbs_driver
);
acpi_sbs_rmdirs
();
return
;
}
...
...
drivers/acpi/sbshc.c
0 → 100644
View file @
e270051d
/*
* SMBus driver for ACPI Embedded Controller (v0.1)
*
* Copyright (c) 2007 Alexey Starikovskiy
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2.
*/
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/actypes.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "sbshc.h"
#define ACPI_SMB_HC_CLASS "smbus_host_controller"
#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
struct
acpi_smb_hc
{
struct
acpi_ec
*
ec
;
struct
mutex
lock
;
wait_queue_head_t
wait
;
u8
offset
;
u8
query_bit
;
smbus_alarm_callback
callback
;
void
*
context
;
};
static
int
acpi_smbus_hc_add
(
struct
acpi_device
*
device
);
static
int
acpi_smbus_hc_remove
(
struct
acpi_device
*
device
,
int
type
);
static
const
struct
acpi_device_id
sbs_device_ids
[]
=
{
{
"ACPI0001"
,
0
},
{
"ACPI0005"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
sbs_device_ids
);
static
struct
acpi_driver
acpi_smb_hc_driver
=
{
.
name
=
"smbus_hc"
,
.
class
=
ACPI_SMB_HC_CLASS
,
.
ids
=
sbs_device_ids
,
.
ops
=
{
.
add
=
acpi_smbus_hc_add
,
.
remove
=
acpi_smbus_hc_remove
,
},
};
union
acpi_smb_status
{
u8
raw
;
struct
{
u8
status
:
5
;
u8
reserved
:
1
;
u8
alarm
:
1
;
u8
done
:
1
;
}
fields
;
};
enum
acpi_smb_status_codes
{
SMBUS_OK
=
0
,
SMBUS_UNKNOWN_FAILURE
=
0x07
,
SMBUS_DEVICE_ADDRESS_NACK
=
0x10
,
SMBUS_DEVICE_ERROR
=
0x11
,
SMBUS_DEVICE_COMMAND_ACCESS_DENIED
=
0x12
,
SMBUS_UNKNOWN_ERROR
=
0x13
,
SMBUS_DEVICE_ACCESS_DENIED
=
0x17
,
SMBUS_TIMEOUT
=
0x18
,
SMBUS_HOST_UNSUPPORTED_PROTOCOL
=
0x19
,
SMBUS_BUSY
=
0x1a
,
SMBUS_PEC_ERROR
=
0x1f
,
};
enum
acpi_smb_offset
{
ACPI_SMB_PROTOCOL
=
0
,
/* protocol, PEC */
ACPI_SMB_STATUS
=
1
,
/* status */
ACPI_SMB_ADDRESS
=
2
,
/* address */
ACPI_SMB_COMMAND
=
3
,
/* command */
ACPI_SMB_DATA
=
4
,
/* 32 data registers */
ACPI_SMB_BLOCK_COUNT
=
0x24
,
/* number of data bytes */
ACPI_SMB_ALARM_ADDRESS
=
0x25
,
/* alarm address */
ACPI_SMB_ALARM_DATA
=
0x26
,
/* 2 bytes alarm data */
};
static
inline
int
smb_hc_read
(
struct
acpi_smb_hc
*
hc
,
u8
address
,
u8
*
data
)
{
return
ec_read
(
hc
->
offset
+
address
,
data
);
}
static
inline
int
smb_hc_write
(
struct
acpi_smb_hc
*
hc
,
u8
address
,
u8
data
)
{
return
ec_write
(
hc
->
offset
+
address
,
data
);
}
static
inline
int
smb_check_done
(
struct
acpi_smb_hc
*
hc
)
{
union
acpi_smb_status
status
=
{.
raw
=
0
};
smb_hc_read
(
hc
,
ACPI_SMB_STATUS
,
&
status
.
raw
);
return
status
.
fields
.
done
&&
(
status
.
fields
.
status
==
SMBUS_OK
);
}
static
int
wait_transaction_complete
(
struct
acpi_smb_hc
*
hc
,
int
timeout
)
{
if
(
wait_event_timeout
(
hc
->
wait
,
smb_check_done
(
hc
),
msecs_to_jiffies
(
timeout
)))
return
0
;
else
return
-
ETIME
;
}
int
acpi_smbus_transaction
(
struct
acpi_smb_hc
*
hc
,
u8
protocol
,
u8
address
,
u8
command
,
u8
*
data
,
u8
length
)
{
int
ret
=
-
EFAULT
,
i
;
u8
temp
,
sz
=
0
;
mutex_lock
(
&
hc
->
lock
);
if
(
smb_hc_read
(
hc
,
ACPI_SMB_PROTOCOL
,
&
temp
))
goto
end
;
if
(
temp
)
{
ret
=
-
EBUSY
;
goto
end
;
}
smb_hc_write
(
hc
,
ACPI_SMB_COMMAND
,
command
);
smb_hc_write
(
hc
,
ACPI_SMB_COMMAND
,
command
);
if
(
!
(
protocol
&
0x01
))
{
smb_hc_write
(
hc
,
ACPI_SMB_BLOCK_COUNT
,
length
);
for
(
i
=
0
;
i
<
length
;
++
i
)
smb_hc_write
(
hc
,
ACPI_SMB_DATA
+
i
,
data
[
i
]);
}
smb_hc_write
(
hc
,
ACPI_SMB_ADDRESS
,
address
<<
1
);
smb_hc_write
(
hc
,
ACPI_SMB_PROTOCOL
,
protocol
);
/*
* Wait for completion. Save the status code, data size,
* and data into the return package (if required by the protocol).
*/
ret
=
wait_transaction_complete
(
hc
,
1000
);
if
(
ret
||
!
(
protocol
&
0x01
))
goto
end
;
switch
(
protocol
)
{
case
SMBUS_RECEIVE_BYTE
:
case
SMBUS_READ_BYTE
:
sz
=
1
;
break
;
case
SMBUS_READ_WORD
:
sz
=
2
;
break
;
case
SMBUS_READ_BLOCK
:
if
(
smb_hc_read
(
hc
,
ACPI_SMB_BLOCK_COUNT
,
&
sz
))
{
ret
=
-
EFAULT
;
goto
end
;
}
sz
&=
0x1f
;
break
;
}
for
(
i
=
0
;
i
<
sz
;
++
i
)
smb_hc_read
(
hc
,
ACPI_SMB_DATA
+
i
,
&
data
[
i
]);
end:
mutex_unlock
(
&
hc
->
lock
);
return
ret
;
}
int
acpi_smbus_read
(
struct
acpi_smb_hc
*
hc
,
u8
protocol
,
u8
address
,
u8
command
,
u8
*
data
)
{
return
acpi_smbus_transaction
(
hc
,
protocol
,
address
,
command
,
data
,
0
);
}
EXPORT_SYMBOL_GPL
(
acpi_smbus_read
);
int
acpi_smbus_write
(
struct
acpi_smb_hc
*
hc
,
u8
protocol
,
u8
address
,
u8
command
,
u8
*
data
,
u8
length
)
{
return
acpi_smbus_transaction
(
hc
,
protocol
,
address
,
command
,
data
,
length
);
}
EXPORT_SYMBOL_GPL
(
acpi_smbus_write
);
int
acpi_smbus_register_callback
(
struct
acpi_smb_hc
*
hc
,
smbus_alarm_callback
callback
,
void
*
context
)
{
mutex_lock
(
&
hc
->
lock
);
hc
->
callback
=
callback
;
hc
->
context
=
context
;
mutex_unlock
(
&
hc
->
lock
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
acpi_smbus_register_callback
);
int
acpi_smbus_unregister_callback
(
struct
acpi_smb_hc
*
hc
)
{
mutex_lock
(
&
hc
->
lock
);
hc
->
callback
=
NULL
;
hc
->
context
=
NULL
;
mutex_unlock
(
&
hc
->
lock
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
acpi_smbus_unregister_callback
);
static
void
acpi_smbus_callback
(
void
*
context
)
{
struct
acpi_smb_hc
*
hc
=
context
;
if
(
hc
->
callback
)
hc
->
callback
(
hc
->
context
);
}
static
int
smbus_alarm
(
void
*
context
)
{
struct
acpi_smb_hc
*
hc
=
context
;
union
acpi_smb_status
status
;
if
(
smb_hc_read
(
hc
,
ACPI_SMB_STATUS
,
&
status
.
raw
))
return
0
;
/* Check if it is only a completion notify */
if
(
status
.
fields
.
done
)
wake_up
(
&
hc
->
wait
);
if
(
!
status
.
fields
.
alarm
)
return
0
;
mutex_lock
(
&
hc
->
lock
);
smb_hc_write
(
hc
,
ACPI_SMB_STATUS
,
status
.
raw
);
if
(
hc
->
callback
)
acpi_os_execute
(
OSL_GPE_HANDLER
,
acpi_smbus_callback
,
hc
);
mutex_unlock
(
&
hc
->
lock
);
return
0
;
}
typedef
int
(
*
acpi_ec_query_func
)
(
void
*
data
);
extern
int
acpi_ec_add_query_handler
(
struct
acpi_ec
*
ec
,
u8
query_bit
,
acpi_handle
handle
,
acpi_ec_query_func
func
,
void
*
data
);
static
int
acpi_smbus_hc_add
(
struct
acpi_device
*
device
)
{
int
status
;
unsigned
long
val
;
struct
acpi_smb_hc
*
hc
;
if
(
!
device
)
return
-
EINVAL
;
status
=
acpi_evaluate_integer
(
device
->
handle
,
"_EC"
,
NULL
,
&
val
);
if
(
ACPI_FAILURE
(
status
))
{
printk
(
KERN_ERR
PREFIX
"error obtaining _EC.
\n
"
);
return
-
EIO
;
}
strcpy
(
acpi_device_name
(
device
),
ACPI_SMB_HC_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ACPI_SMB_HC_CLASS
);
hc
=
kzalloc
(
sizeof
(
struct
acpi_smb_hc
),
GFP_KERNEL
);
if
(
!
hc
)
return
-
ENOMEM
;
mutex_init
(
&
hc
->
lock
);
init_waitqueue_head
(
&
hc
->
wait
);
hc
->
ec
=
acpi_driver_data
(
device
->
parent
);
hc
->
offset
=
(
val
>>
8
)
&
0xff
;
hc
->
query_bit
=
val
&
0xff
;
acpi_driver_data
(
device
)
=
hc
;
acpi_ec_add_query_handler
(
hc
->
ec
,
hc
->
query_bit
,
NULL
,
smbus_alarm
,
hc
);
printk
(
KERN_INFO
PREFIX
"SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x
\n
"
,
hc
->
ec
,
hc
->
offset
,
hc
->
query_bit
);
return
0
;
}
extern
void
acpi_ec_remove_query_handler
(
struct
acpi_ec
*
ec
,
u8
query_bit
);
static
int
acpi_smbus_hc_remove
(
struct
acpi_device
*
device
,
int
type
)
{
struct
acpi_smb_hc
*
hc
;
if
(
!
device
)
return
-
EINVAL
;
hc
=
acpi_driver_data
(
device
);
acpi_ec_remove_query_handler
(
hc
->
ec
,
hc
->
query_bit
);
kfree
(
hc
);
return
0
;
}
static
int
__init
acpi_smb_hc_init
(
void
)
{
int
result
;
result
=
acpi_bus_register_driver
(
&
acpi_smb_hc_driver
);
if
(
result
<
0
)
return
-
ENODEV
;
return
0
;
}
static
void
__exit
acpi_smb_hc_exit
(
void
)
{
acpi_bus_unregister_driver
(
&
acpi_smb_hc_driver
);
}
module_init
(
acpi_smb_hc_init
);
module_exit
(
acpi_smb_hc_exit
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Alexey Starikovskiy"
);
MODULE_DESCRIPTION
(
"ACPI SMBus HC driver"
);
drivers/acpi/sbshc.h
0 → 100644
View file @
e270051d
struct
acpi_smb_hc
;
enum
acpi_smb_protocol
{
SMBUS_WRITE_QUICK
=
2
,
SMBUS_READ_QUICK
=
3
,
SMBUS_SEND_BYTE
=
4
,
SMBUS_RECEIVE_BYTE
=
5
,
SMBUS_WRITE_BYTE
=
6
,
SMBUS_READ_BYTE
=
7
,
SMBUS_WRITE_WORD
=
8
,
SMBUS_READ_WORD
=
9
,
SMBUS_WRITE_BLOCK
=
0xa
,
SMBUS_READ_BLOCK
=
0xb
,
SMBUS_PROCESS_CALL
=
0xc
,
SMBUS_BLOCK_PROCESS_CALL
=
0xd
,
};
static
const
u8
SMBUS_PEC
=
0x80
;
typedef
void
(
*
smbus_alarm_callback
)(
void
*
context
);
extern
int
acpi_smbus_read
(
struct
acpi_smb_hc
*
hc
,
u8
protocol
,
u8
address
,
u8
command
,
u8
*
data
);
extern
int
acpi_smbus_write
(
struct
acpi_smb_hc
*
hc
,
u8
protocol
,
u8
slave_address
,
u8
command
,
u8
*
data
,
u8
length
);
extern
int
acpi_smbus_register_callback
(
struct
acpi_smb_hc
*
hc
,
smbus_alarm_callback
callback
,
void
*
context
);
extern
int
acpi_smbus_unregister_callback
(
struct
acpi_smb_hc
*
hc
);
include/acpi/acpi_bus.h
View file @
e270051d
...
...
@@ -333,6 +333,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state);
int
acpi_bus_set_power
(
acpi_handle
handle
,
int
state
);
#ifdef CONFIG_ACPI_PROC_EVENT
int
acpi_bus_generate_proc_event
(
struct
acpi_device
*
device
,
u8
type
,
int
data
);
int
acpi_bus_generate_proc_event4
(
const
char
*
class
,
const
char
*
bid
,
u8
type
,
int
data
);
int
acpi_bus_receive_event
(
struct
acpi_bus_event
*
event
);
#else
static
inline
int
acpi_bus_generate_proc_event
(
struct
acpi_device
*
device
,
u8
type
,
int
data
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment