sbs.c 21.9 KB
Newer Older
1
/*
2
 *  sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0 $)
3
 *
4 5
 *  Copyright (c) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
 *  Copyright (c) 2005-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 *  Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  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; either version 2 of the License, or (at
 *  your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
35
#include <linux/timer.h>
36
#include <linux/jiffies.h>
37 38
#include <linux/delay.h>

39 40
#include "sbshc.h"

41 42 43 44 45 46 47 48 49 50 51
#define ACPI_SBS_COMPONENT		0x00080000
#define ACPI_SBS_CLASS			"sbs"
#define ACPI_AC_CLASS			"ac_adapter"
#define ACPI_BATTERY_CLASS		"battery"
#define ACPI_SBS_DEVICE_NAME		"Smart Battery System"
#define ACPI_SBS_FILE_INFO		"info"
#define ACPI_SBS_FILE_STATE		"state"
#define ACPI_SBS_FILE_ALARM		"alarm"
#define ACPI_BATTERY_DIR_NAME		"BAT%i"
#define ACPI_AC_DIR_NAME		"AC0"

52 53 54 55 56 57 58 59
enum acpi_sbs_device_addr {
	ACPI_SBS_CHARGER = 0x9,
	ACPI_SBS_MANAGER = 0xa,
	ACPI_SBS_BATTERY = 0xb,
};

#define ACPI_SBS_NOTIFY_STATUS		0x80
#define ACPI_SBS_NOTIFY_INFO		0x81
60

61
ACPI_MODULE_NAME("sbs");
62

63
MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
64 65 66
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_LICENSE("GPL");

67 68 69
static unsigned int cache_time = 1000;
module_param(cache_time, uint, 0644);
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
70 71 72 73 74 75

extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);

76
#define MAX_SBS_BAT			4
77 78
#define ACPI_SBS_BLOCK_MAX		32

79 80
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
81
static int acpi_sbs_resume(struct acpi_device *device);
82

83
static const struct acpi_device_id sbs_device_ids[] = {
84
	{"ACPI0002", 0},
85 86 87 88
	{"", 0},
};
MODULE_DEVICE_TABLE(acpi, sbs_device_ids);

89
static struct acpi_driver acpi_sbs_driver = {
L
Len Brown 已提交
90
	.name = "sbs",
91
	.class = ACPI_SBS_CLASS,
92
	.ids = sbs_device_ids,
93 94 95
	.ops = {
		.add = acpi_sbs_add,
		.remove = acpi_sbs_remove,
96
		.resume = acpi_sbs_resume,
97 98 99 100 101
		},
};

struct acpi_battery {
	struct acpi_sbs *sbs;
102
	struct proc_dir_entry *proc_entry;
103 104
	unsigned long update_time;
	char name[8];
105 106 107
	char manufacturer_name[ACPI_SBS_BLOCK_MAX];
	char device_name[ACPI_SBS_BLOCK_MAX];
	char device_chemistry[ACPI_SBS_BLOCK_MAX];
108
	u32 alarm_capacity;
109 110 111 112
	u16 full_charge_capacity;
	u16 design_capacity;
	u16 design_voltage;
	u16 serial_number;
113 114
	u16 cycle_count;
	u16 temp_now;
115 116
	u16 voltage_now;
	s16 current_now;
117
	s16 current_avg;
118
	u16 capacity_now;
119
	u16 state_of_charge;
120 121
	u16 state;
	u16 mode;
122
	u16 spec;
123 124
	u8 id;
	u8 present:1;
125 126 127 128
};

struct acpi_sbs {
	struct acpi_device *device;
129
	struct acpi_smb_hc *hc;
130 131
	struct mutex lock;
	struct proc_dir_entry *charger_entry;
132
	struct acpi_battery battery[MAX_SBS_BAT];
133
	u8 batteries_supported:4;
134 135
	u8 manager_present:1;
	u8 charger_present:1;
136 137
};

138
static inline int battery_scale(int log)
139
{
140 141 142 143
	int scale = 1;
	while (log--)
		scale *= 10;
	return scale;
144 145
}

146
static inline int acpi_battery_vscale(struct acpi_battery *battery)
147
{
148
	return battery_scale((battery->spec & 0x0f00) >> 8);
149 150
}

151
static inline int acpi_battery_ipscale(struct acpi_battery *battery)
152
{
153
	return battery_scale((battery->spec & 0xf000) >> 12);
154 155
}

156
static inline int acpi_battery_mode(struct acpi_battery *battery)
157
{
158
	return (battery->mode & 0x8000);
159
}
160

161
static inline int acpi_battery_scale(struct acpi_battery *battery)
162
{
163 164
	return (acpi_battery_mode(battery) ? 10 : 1) *
	    acpi_battery_ipscale(battery);
165 166
}

167 168 169
/* --------------------------------------------------------------------------
                            Smart Battery System Management
   -------------------------------------------------------------------------- */
170

171 172 173 174 175
struct acpi_battery_reader {
	u8 command;		/* command for battery */
	u8 mode;		/* word or block? */
	size_t offset;		/* offset inside struct acpi_sbs_battery */
};
176

177 178 179 180 181 182 183 184 185 186 187 188 189
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)},
};
190

191 192 193 194 195 196 197 198 199
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)},
};
200

201
static int acpi_manager_get_info(struct acpi_sbs *sbs)
202 203
{
	int result = 0;
204
	u16 battery_system_info;
205

206 207 208 209
	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;
210
	return result;
211 212 213 214
}

static int acpi_battery_get_info(struct acpi_battery *battery)
{
215
	int i, result = 0;
216

217 218 219 220 221 222
	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;
223
	}
224
	return result;
225 226 227 228
}

static int acpi_battery_get_state(struct acpi_battery *battery)
{
229
	int i, result = 0;
230

231 232 233 234 235 236 237 238 239 240 241
	if (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)
242 243 244
			goto end;
	}
      end:
245
	battery->update_time = jiffies;
246
	return result;
247 248
}

249
static int acpi_battery_get_alarm(struct acpi_battery *battery)
250
{
251 252 253
	return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
				 ACPI_SBS_BATTERY, 0x01,
				 (u8 *) & battery->alarm_capacity);
254 255
}

256
static int acpi_battery_set_alarm(struct acpi_battery *battery)
257
{
258 259 260
	struct acpi_sbs *sbs = battery->sbs;
	u16 value;
	return 0;
261

262 263 264 265 266 267 268
	if (sbs->manager_present) {
		acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
				0x01, (u8 *)&value);
		value &= 0x0fff;
		value |= 1 << (battery->id + 12);
		acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER,
				0x01, (u8 *)&value, 2);
269
	}
270 271 272
	value = battery->alarm_capacity / (acpi_battery_mode(battery) ? 10 : 1);
	return acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY,
				0x01, (u8 *)&value, 2);
273 274 275 276
}

static int acpi_ac_get_present(struct acpi_sbs *sbs)
{
277 278
	int result;
	u16 status;
279

280 281 282 283
	result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER,
				 0x13, (u8 *) & status);
	if (!result)
		sbs->charger_present = (status >> 15) & 0x1;
284
	return result;
285 286 287 288 289 290 291 292 293
}

/* --------------------------------------------------------------------------
                              FS Interface (/proc/acpi)
   -------------------------------------------------------------------------- */

/* Generic Routines */

static int
294
acpi_sbs_add_fs(struct proc_dir_entry **dir,
295 296 297 298 299 300 301 302 303 304 305
			struct proc_dir_entry *parent_dir,
			char *dir_name,
			struct file_operations *info_fops,
			struct file_operations *state_fops,
			struct file_operations *alarm_fops, void *data)
{
	struct proc_dir_entry *entry = NULL;

	if (!*dir) {
		*dir = proc_mkdir(dir_name, parent_dir);
		if (!*dir) {
306 307
			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
					"proc_mkdir() failed"));
308
			return -ENODEV;
309 310 311 312 313 314 315 316
		}
		(*dir)->owner = THIS_MODULE;
	}

	/* 'info' [R] */
	if (info_fops) {
		entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
		if (!entry) {
317 318
			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
					"create_proc_entry() failed"));
319 320 321 322 323 324 325 326 327 328 329
		} else {
			entry->proc_fops = info_fops;
			entry->data = data;
			entry->owner = THIS_MODULE;
		}
	}

	/* 'state' [R] */
	if (state_fops) {
		entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
		if (!entry) {
330 331
			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
					"create_proc_entry() failed"));
332 333 334 335 336 337 338 339 340 341 342
		} else {
			entry->proc_fops = state_fops;
			entry->data = data;
			entry->owner = THIS_MODULE;
		}
	}

	/* 'alarm' [R/W] */
	if (alarm_fops) {
		entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
		if (!entry) {
343 344
			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
					"create_proc_entry() failed"));
345 346 347 348 349 350 351
		} else {
			entry->proc_fops = alarm_fops;
			entry->data = data;
			entry->owner = THIS_MODULE;
		}
	}

352
	return 0;
353 354 355
}

static void
356
acpi_sbs_remove_fs(struct proc_dir_entry **dir,
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
			   struct proc_dir_entry *parent_dir)
{

	if (*dir) {
		remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
		remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
		remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);
		remove_proc_entry((*dir)->name, parent_dir);
		*dir = NULL;
	}

}

/* Smart Battery Interface */

static struct proc_dir_entry *acpi_battery_dir = NULL;

374 375 376 377 378 379
static inline char *acpi_battery_units(struct acpi_battery *battery)
{
	return acpi_battery_mode(battery) ? " mWh" : " mAh";
}


380 381
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
382
	struct acpi_battery *battery = seq->private;
383
	struct acpi_sbs *sbs = battery->sbs;
384 385
	int result = 0;

386
	mutex_lock(&sbs->lock);
387

388 389 390
	seq_printf(seq, "present:                 %s\n",
		   (battery->present) ? "yes" : "no");
	if (!battery->present)
391
		goto end;
392

393
	seq_printf(seq, "design capacity:         %i%s\n",
394 395
		   battery->design_capacity * acpi_battery_scale(battery),
		   acpi_battery_units(battery));
396
	seq_printf(seq, "last full capacity:      %i%s\n",
397 398
		   battery->full_charge_capacity * acpi_battery_scale(battery),
		   acpi_battery_units(battery));
399 400
	seq_printf(seq, "battery technology:      rechargeable\n");
	seq_printf(seq, "design voltage:          %i mV\n",
401
		   battery->design_voltage * acpi_battery_vscale(battery));
402 403 404 405
	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");
406
	seq_printf(seq, "model number:            %s\n", battery->device_name);
407
	seq_printf(seq, "serial number:           %i\n",
408
		   battery->serial_number);
409
	seq_printf(seq, "battery type:            %s\n",
410
		   battery->device_chemistry);
411
	seq_printf(seq, "OEM info:                %s\n",
412
		   battery->manufacturer_name);
413
      end:
414
	mutex_unlock(&sbs->lock);
415
	return result;
416 417 418 419 420 421 422 423 424
}

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)
{
425 426
	struct acpi_battery *battery = seq->private;
	struct acpi_sbs *sbs = battery->sbs;
427 428
	int result = 0;

429 430 431 432
	mutex_lock(&sbs->lock);
	seq_printf(seq, "present:                 %s\n",
		   (battery->present) ? "yes" : "no");
	if (!battery->present)
433 434
		goto end;

435 436 437 438 439 440 441 442
	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));
443
	seq_printf(seq, "remaining capacity:      %i%s\n",
444 445
		   battery->capacity_now * acpi_battery_scale(battery),
		   acpi_battery_units(battery));
446
	seq_printf(seq, "present voltage:         %i mV\n",
447
		   battery->voltage_now * acpi_battery_vscale(battery));
448 449

      end:
450
	mutex_unlock(&sbs->lock);
451
	return result;
452 453 454 455 456 457 458 459 460
}

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_read_alarm(struct seq_file *seq, void *offset)
{
461
	struct acpi_battery *battery = seq->private;
462
	struct acpi_sbs *sbs = battery->sbs;
463 464
	int result = 0;

465
	mutex_lock(&sbs->lock);
466

467
	if (!battery->present) {
468 469 470 471
		seq_printf(seq, "present:                 no\n");
		goto end;
	}

472
	acpi_battery_get_alarm(battery);
473
	seq_printf(seq, "alarm:                   ");
474
	if (battery->alarm_capacity)
475
		seq_printf(seq, "%i%s\n",
476 477 478 479
			   battery->alarm_capacity *
			   acpi_battery_scale(battery),
			   acpi_battery_units(battery));
	else
480 481
		seq_printf(seq, "disabled\n");
      end:
482
	mutex_unlock(&sbs->lock);
483
	return result;
484 485 486 487 488 489
}

static ssize_t
acpi_battery_write_alarm(struct file *file, const char __user * buffer,
			 size_t count, loff_t * ppos)
{
490 491
	struct seq_file *seq = file->private_data;
	struct acpi_battery *battery = seq->private;
492
	struct acpi_sbs *sbs = battery->sbs;
493
	char alarm_string[12] = { '\0' };
494 495
	int result = 0;
	mutex_lock(&sbs->lock);
496
	if (!battery->present) {
497 498 499 500 501 502 503 504 505 506 507 508
		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;
509 510
	battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0);
	acpi_battery_set_alarm(battery);
511
      end:
512 513
	mutex_unlock(&sbs->lock);
	if (result)
514
		return result;
515
	return count;
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
}

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 file_operations acpi_battery_info_fops = {
	.open = acpi_battery_info_open_fs,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
	.owner = THIS_MODULE,
};

static struct file_operations acpi_battery_state_fops = {
	.open = acpi_battery_state_open_fs,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
	.owner = THIS_MODULE,
};

static struct file_operations acpi_battery_alarm_fops = {
	.open = acpi_battery_alarm_open_fs,
	.read = seq_read,
	.write = acpi_battery_write_alarm,
	.llseek = seq_lseek,
	.release = single_release,
	.owner = THIS_MODULE,
};

/* Legacy AC Adapter Interface */

static struct proc_dir_entry *acpi_ac_dir = NULL;

static int acpi_ac_read_state(struct seq_file *seq, void *offset)
{

555
	struct acpi_sbs *sbs = seq->private;
556

557
	mutex_lock(&sbs->lock);
558 559

	seq_printf(seq, "state:                   %s\n",
560
		   sbs->charger_present ? "on-line" : "off-line");
561

562
	mutex_unlock(&sbs->lock);
563
	return 0;
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
}

static int acpi_ac_state_open_fs(struct inode *inode, struct file *file)
{
	return single_open(file, acpi_ac_read_state, PDE(inode)->data);
}

static struct file_operations acpi_ac_state_fops = {
	.open = acpi_ac_state_open_fs,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
	.owner = THIS_MODULE,
};

/* --------------------------------------------------------------------------
                                 Driver Interface
   -------------------------------------------------------------------------- */

/* Smart Battery */

585
static int acpi_battery_read(struct acpi_battery *battery)
586
{
587 588
	int result = 0, saved_present = battery->present;
	u16 state;
589

590 591 592 593 594 595 596 597 598 599 600 601 602
	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;
603

604 605 606 607 608 609 610 611 612
	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;
}
613

614 615 616 617
static int acpi_battery_add(struct acpi_sbs *sbs, int id)
{
	int result;
	struct acpi_battery *battery = &sbs->battery[id];
618 619
	battery->id = id;
	battery->sbs = sbs;
620 621 622 623
	battery->update_time = 0;
	result = acpi_battery_read(battery);
	if (result)
		return result;
624

625 626 627 628 629
	sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id);
	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);
630
	printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
631 632
	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
	       battery->name, sbs->battery->present ? "present" : "absent");
633
	return result;
634 635 636 637 638
}

static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
{

639
	if (sbs->battery[id].proc_entry) {
640 641
		acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry),
				   acpi_battery_dir);
642 643 644
	}
}

645
static int acpi_charger_add(struct acpi_sbs *sbs)
646 647 648 649
{
	int result;

	result = acpi_ac_get_present(sbs);
650
	if (result)
651
		goto end;
652 653 654 655
	result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir,
				 ACPI_AC_DIR_NAME, NULL,
				 &acpi_ac_state_fops, NULL, sbs);
	if (result)
656
		goto end;
657 658
	printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
659
	       ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
660
      end:
661
	return result;
662 663
}

664
static void acpi_charger_remove(struct acpi_sbs *sbs)
665 666
{

667 668
	if (sbs->charger_entry)
		acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
669 670
}

671
void acpi_sbs_callback(void *context)
672
{
673 674 675 676 677 678 679 680 681 682
	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) {
		acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
					      ACPI_SBS_NOTIFY_STATUS,
					      sbs->charger_present);
683
	}
684 685 686 687 688 689 690 691 692 693 694 695 696
	if (sbs->manager_present) {
		for (id = 0; id < MAX_SBS_BAT; ++id) {
			if (!(sbs->batteries_supported & (1 << id)))
				continue;
			bat = &sbs->battery[id];
			saved_battery_state = bat->present;
			acpi_battery_read(bat);
			if (saved_battery_state == bat->present)
				continue;
			acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
						      bat->name,
						      ACPI_SBS_NOTIFY_STATUS,
						      bat->present);
697 698 699 700
		}
	}
}

701
static int acpi_sbs_remove(struct acpi_device *device, int type);
702 703 704

static int acpi_sbs_add(struct acpi_device *device)
{
705 706
	struct acpi_sbs *sbs;
	int result = 0;
707
	int id;
708

709
	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
710
	if (!sbs) {
711 712
		result = -ENOMEM;
		goto end;
713 714
	}

715
	mutex_init(&sbs->lock);
716

717
	sbs->hc = acpi_driver_data(device->parent);
718
	sbs->device = device;
719 720 721 722
	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
	acpi_driver_data(device) = sbs;

723
	result = acpi_charger_add(sbs);
724 725
	if (result)
		goto end;
726

727 728 729 730 731 732 733 734 735
	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);
736
      end:
737 738
	if (result)
		acpi_sbs_remove(device, 0);
739
	return result;
740 741
}

742
static int acpi_sbs_remove(struct acpi_device *device, int type)
743
{
L
Len Brown 已提交
744
	struct acpi_sbs *sbs;
745 746
	int id;

747
	if (!device)
748
		return -EINVAL;
749
	sbs = acpi_driver_data(device);
750
	if (!sbs)
751
		return -EINVAL;
752 753 754
	mutex_lock(&sbs->lock);
	acpi_smbus_unregister_callback(sbs->hc);
	for (id = 0; id < MAX_SBS_BAT; ++id)
755
		acpi_battery_remove(sbs, id);
756 757 758
	acpi_charger_remove(sbs);
	mutex_unlock(&sbs->lock);
	mutex_destroy(&sbs->lock);
759
	kfree(sbs);
760
	return 0;
761 762
}

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
static void acpi_sbs_rmdirs(void)
{
	if (acpi_ac_dir) {
		acpi_unlock_ac_dir(acpi_ac_dir);
		acpi_ac_dir = NULL;
	}
	if (acpi_battery_dir) {
		acpi_unlock_battery_dir(acpi_battery_dir);
		acpi_battery_dir = NULL;
	}
}

static int acpi_sbs_resume(struct acpi_device *device)
{
	struct acpi_sbs *sbs;
	if (!device)
		return -EINVAL;
	sbs = device->driver_data;
781
	acpi_sbs_callback(sbs);
782 783 784
	return 0;
}

785 786 787 788
static int __init acpi_sbs_init(void)
{
	int result = 0;

789 790 791
	if (acpi_disabled)
		return -ENODEV;

792 793
	acpi_ac_dir = acpi_lock_ac_dir();
	if (!acpi_ac_dir) {
794 795
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"acpi_lock_ac_dir() failed"));
796
		return -ENODEV;
797 798 799 800
	}

	acpi_battery_dir = acpi_lock_battery_dir();
	if (!acpi_battery_dir) {
801 802
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"acpi_lock_battery_dir() failed"));
803
		acpi_sbs_rmdirs();
804
		return -ENODEV;
805 806 807 808
	}

	result = acpi_bus_register_driver(&acpi_sbs_driver);
	if (result < 0) {
809 810
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"acpi_bus_register_driver() failed"));
811
		acpi_sbs_rmdirs();
812
		return -ENODEV;
813 814
	}

815
	return 0;
816 817 818 819 820 821
}

static void __exit acpi_sbs_exit(void)
{
	acpi_bus_unregister_driver(&acpi_sbs_driver);

822
	acpi_sbs_rmdirs();
823

824
	return;
825 826 827 828
}

module_init(acpi_sbs_init);
module_exit(acpi_sbs_exit);