Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] apm_emu: Use generic apm-emulation

This patch removes a huge amount of code that is now in common code
in drivers/char/apm-emulation.c

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>

authored by

Johannes Berg and committed by
Paul Mackerras
b3028878 6bfeccdc

+48 -476
+3
arch/powerpc/Kconfig
··· 117 117 default y 118 118 depends on BUG 119 119 120 + config SYS_SUPPORTS_APM_EMULATION 121 + bool 122 + 120 123 config DEFAULT_UIMAGE 121 124 bool 122 125 help
+3 -1
drivers/macintosh/Kconfig
··· 109 109 110 110 config PMAC_APM_EMU 111 111 tristate "APM emulation" 112 - depends on PPC_PMAC && PPC32 && PM && ADB_PMU 112 + select SYS_SUPPORTS_APM_EMULATION 113 + select APM_EMULATION 114 + depends on ADB_PMU && PM 113 115 114 116 config PMAC_MEDIABAY 115 117 bool "Support PowerBook hotswap media bay"
+42 -475
drivers/macintosh/apm_emu.c
··· 1 - /* APM emulation layer for PowerMac 2 - * 3 - * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) 1 + /* 2 + * APM emulation for PMU-based machines 4 3 * 5 - * Lots of code inherited from apm.c, see appropriate notice in 6 - * arch/i386/kernel/apm.c 4 + * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org) 7 5 * 8 6 * This program is free software; you can redistribute it and/or modify it 9 7 * under the terms of the GNU General Public License as published by the ··· 16 18 * 17 19 */ 18 20 19 - #include <linux/module.h> 20 - 21 - #include <linux/poll.h> 22 - #include <linux/types.h> 23 - #include <linux/stddef.h> 24 - #include <linux/timer.h> 25 - #include <linux/fcntl.h> 26 - #include <linux/slab.h> 27 - #include <linux/stat.h> 28 - #include <linux/proc_fs.h> 29 - #include <linux/miscdevice.h> 30 - #include <linux/apm_bios.h> 31 - #include <linux/init.h> 32 - #include <linux/sched.h> 33 - #include <linux/pm.h> 34 21 #include <linux/kernel.h> 35 - #include <linux/smp_lock.h> 36 - 22 + #include <linux/module.h> 23 + #include <linux/apm-emulation.h> 37 24 #include <linux/adb.h> 38 25 #include <linux/pmu.h> 39 - 40 - #include <asm/system.h> 41 - #include <asm/uaccess.h> 42 - #include <asm/machdep.h> 43 - 44 - #undef DEBUG 45 - 46 - #ifdef DEBUG 47 - #define DBG(args...) printk(KERN_DEBUG args) 48 - //#define DBG(args...) xmon_printf(args) 49 - #else 50 - #define DBG(args...) do { } while (0) 51 - #endif 52 - 53 - /* 54 - * The apm_bios device is one of the misc char devices. 55 - * This is its minor number. 56 - */ 57 - #define APM_MINOR_DEV 134 58 - 59 - /* 60 - * Maximum number of events stored 61 - */ 62 - #define APM_MAX_EVENTS 20 63 - 64 - #define FAKE_APM_BIOS_VERSION 0x0101 65 - 66 - #define APM_USER_NOTIFY_TIMEOUT (5*HZ) 67 - 68 - /* 69 - * The per-file APM data 70 - */ 71 - struct apm_user { 72 - int magic; 73 - struct apm_user * next; 74 - int suser: 1; 75 - int suspend_waiting: 1; 76 - int suspends_pending; 77 - int suspends_read; 78 - int event_head; 79 - int event_tail; 80 - apm_event_t events[APM_MAX_EVENTS]; 81 - }; 82 - 83 - /* 84 - * The magic number in apm_user 85 - */ 86 - #define APM_BIOS_MAGIC 0x4101 87 - 88 - /* 89 - * Local variables 90 - */ 91 - static int suspends_pending; 92 - 93 - static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); 94 - static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); 95 - static struct apm_user * user_list; 96 - 97 - static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when); 98 - static struct pmu_sleep_notifier apm_sleep_notifier = { 99 - apm_notify_sleep, 100 - SLEEP_LEVEL_USERLAND, 101 - }; 102 - 103 - static const char driver_version[] = "0.5"; /* no spaces */ 104 - 105 - #ifdef DEBUG 106 - static char * apm_event_name[] = { 107 - "system standby", 108 - "system suspend", 109 - "normal resume", 110 - "critical resume", 111 - "low battery", 112 - "power status change", 113 - "update time", 114 - "critical suspend", 115 - "user standby", 116 - "user suspend", 117 - "system standby resume", 118 - "capabilities change" 119 - }; 120 - #define NR_APM_EVENT_NAME \ 121 - (sizeof(apm_event_name) / sizeof(apm_event_name[0])) 122 - 123 - #endif 124 - 125 - static int queue_empty(struct apm_user *as) 126 - { 127 - return as->event_head == as->event_tail; 128 - } 129 - 130 - static apm_event_t get_queued_event(struct apm_user *as) 131 - { 132 - as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; 133 - return as->events[as->event_tail]; 134 - } 135 - 136 - static void queue_event(apm_event_t event, struct apm_user *sender) 137 - { 138 - struct apm_user * as; 139 - 140 - DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]); 141 - if (user_list == NULL) 142 - return; 143 - for (as = user_list; as != NULL; as = as->next) { 144 - if (as == sender) 145 - continue; 146 - as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; 147 - if (as->event_head == as->event_tail) { 148 - static int notified; 149 - 150 - if (notified++ == 0) 151 - printk(KERN_ERR "apm_emu: an event queue overflowed\n"); 152 - as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; 153 - } 154 - as->events[as->event_head] = event; 155 - if (!as->suser) 156 - continue; 157 - switch (event) { 158 - case APM_SYS_SUSPEND: 159 - case APM_USER_SUSPEND: 160 - as->suspends_pending++; 161 - suspends_pending++; 162 - break; 163 - case APM_NORMAL_RESUME: 164 - as->suspend_waiting = 0; 165 - break; 166 - } 167 - } 168 - wake_up_interruptible(&apm_waitqueue); 169 - } 170 - 171 - static int check_apm_user(struct apm_user *as, const char *func) 172 - { 173 - if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { 174 - printk(KERN_ERR "apm_emu: %s passed bad filp\n", func); 175 - return 1; 176 - } 177 - return 0; 178 - } 179 - 180 - static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) 181 - { 182 - struct apm_user * as; 183 - size_t i; 184 - apm_event_t event; 185 - DECLARE_WAITQUEUE(wait, current); 186 - 187 - as = fp->private_data; 188 - if (check_apm_user(as, "read")) 189 - return -EIO; 190 - if (count < sizeof(apm_event_t)) 191 - return -EINVAL; 192 - if (queue_empty(as)) { 193 - if (fp->f_flags & O_NONBLOCK) 194 - return -EAGAIN; 195 - add_wait_queue(&apm_waitqueue, &wait); 196 - repeat: 197 - set_current_state(TASK_INTERRUPTIBLE); 198 - if (queue_empty(as) && !signal_pending(current)) { 199 - schedule(); 200 - goto repeat; 201 - } 202 - set_current_state(TASK_RUNNING); 203 - remove_wait_queue(&apm_waitqueue, &wait); 204 - } 205 - i = count; 206 - while ((i >= sizeof(event)) && !queue_empty(as)) { 207 - event = get_queued_event(as); 208 - DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]); 209 - if (copy_to_user(buf, &event, sizeof(event))) { 210 - if (i < count) 211 - break; 212 - return -EFAULT; 213 - } 214 - switch (event) { 215 - case APM_SYS_SUSPEND: 216 - case APM_USER_SUSPEND: 217 - as->suspends_read++; 218 - break; 219 - } 220 - buf += sizeof(event); 221 - i -= sizeof(event); 222 - } 223 - if (i < count) 224 - return count - i; 225 - if (signal_pending(current)) 226 - return -ERESTARTSYS; 227 - return 0; 228 - } 229 - 230 - static unsigned int do_poll(struct file *fp, poll_table * wait) 231 - { 232 - struct apm_user * as; 233 - 234 - as = fp->private_data; 235 - if (check_apm_user(as, "poll")) 236 - return 0; 237 - poll_wait(fp, &apm_waitqueue, wait); 238 - if (!queue_empty(as)) 239 - return POLLIN | POLLRDNORM; 240 - return 0; 241 - } 242 - 243 - static int do_ioctl(struct inode * inode, struct file *filp, 244 - u_int cmd, u_long arg) 245 - { 246 - struct apm_user * as; 247 - DECLARE_WAITQUEUE(wait, current); 248 - 249 - as = filp->private_data; 250 - if (check_apm_user(as, "ioctl")) 251 - return -EIO; 252 - if (!as->suser) 253 - return -EPERM; 254 - switch (cmd) { 255 - case APM_IOC_SUSPEND: 256 - /* If a suspend message was sent to userland, we 257 - * consider this as a confirmation message 258 - */ 259 - if (as->suspends_read > 0) { 260 - as->suspends_read--; 261 - as->suspends_pending--; 262 - suspends_pending--; 263 - } else { 264 - // Route to PMU suspend ? 265 - break; 266 - } 267 - as->suspend_waiting = 1; 268 - add_wait_queue(&apm_waitqueue, &wait); 269 - DBG("apm_emu: ioctl waking up sleep waiter !\n"); 270 - wake_up(&apm_suspend_waitqueue); 271 - mb(); 272 - while(as->suspend_waiting && !signal_pending(current)) { 273 - set_current_state(TASK_INTERRUPTIBLE); 274 - schedule(); 275 - } 276 - set_current_state(TASK_RUNNING); 277 - remove_wait_queue(&apm_waitqueue, &wait); 278 - break; 279 - default: 280 - return -EINVAL; 281 - } 282 - return 0; 283 - } 284 - 285 - static int do_release(struct inode * inode, struct file * filp) 286 - { 287 - struct apm_user * as; 288 - 289 - as = filp->private_data; 290 - if (check_apm_user(as, "release")) 291 - return 0; 292 - filp->private_data = NULL; 293 - lock_kernel(); 294 - if (as->suspends_pending > 0) { 295 - suspends_pending -= as->suspends_pending; 296 - if (suspends_pending <= 0) 297 - wake_up(&apm_suspend_waitqueue); 298 - } 299 - if (user_list == as) 300 - user_list = as->next; 301 - else { 302 - struct apm_user * as1; 303 - 304 - for (as1 = user_list; 305 - (as1 != NULL) && (as1->next != as); 306 - as1 = as1->next) 307 - ; 308 - if (as1 == NULL) 309 - printk(KERN_ERR "apm: filp not in user list\n"); 310 - else 311 - as1->next = as->next; 312 - } 313 - unlock_kernel(); 314 - kfree(as); 315 - return 0; 316 - } 317 - 318 - static int do_open(struct inode * inode, struct file * filp) 319 - { 320 - struct apm_user * as; 321 - 322 - as = kmalloc(sizeof(*as), GFP_KERNEL); 323 - if (as == NULL) { 324 - printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", 325 - sizeof(*as)); 326 - return -ENOMEM; 327 - } 328 - as->magic = APM_BIOS_MAGIC; 329 - as->event_tail = as->event_head = 0; 330 - as->suspends_pending = 0; 331 - as->suspends_read = 0; 332 - /* 333 - * XXX - this is a tiny bit broken, when we consider BSD 334 - * process accounting. If the device is opened by root, we 335 - * instantly flag that we used superuser privs. Who knows, 336 - * we might close the device immediately without doing a 337 - * privileged operation -- cevans 338 - */ 339 - as->suser = capable(CAP_SYS_ADMIN); 340 - as->next = user_list; 341 - user_list = as; 342 - filp->private_data = as; 343 - 344 - DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser); 345 - 346 - return 0; 347 - } 348 - 349 - /* Wait for all clients to ack the suspend request. APM API 350 - * doesn't provide a way to NAK, but this could be added 351 - * here. 352 - */ 353 - static void wait_all_suspend(void) 354 - { 355 - DECLARE_WAITQUEUE(wait, current); 356 - 357 - add_wait_queue(&apm_suspend_waitqueue, &wait); 358 - DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending); 359 - while(suspends_pending > 0) { 360 - set_current_state(TASK_UNINTERRUPTIBLE); 361 - schedule(); 362 - } 363 - set_current_state(TASK_RUNNING); 364 - remove_wait_queue(&apm_suspend_waitqueue, &wait); 365 - 366 - DBG("apm_emu: wait_all_suspend() - complete !\n"); 367 - } 368 - 369 - static void apm_notify_sleep(struct pmu_sleep_notifier *self, int when) 370 - { 371 - switch(when) { 372 - case PBOOK_SLEEP_REQUEST: 373 - queue_event(APM_SYS_SUSPEND, NULL); 374 - wait_all_suspend(); 375 - break; 376 - case PBOOK_WAKE: 377 - queue_event(APM_NORMAL_RESUME, NULL); 378 - break; 379 - } 380 - } 381 26 382 27 #define APM_CRITICAL 10 383 28 #define APM_LOW 30 384 29 385 - static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length) 30 + static void pmu_apm_get_power_status(struct apm_power_info *info) 386 31 { 387 - /* Arguments, with symbols from linux/apm_bios.h. Information is 388 - from the Get Power Status (0x0a) call unless otherwise noted. 32 + int percentage = -1; 33 + int batteries = 0; 34 + int time_units = -1; 35 + int real_count = 0; 36 + int i; 37 + char charging = 0; 38 + long charge = -1; 39 + long amperage = 0; 40 + unsigned long btype = 0; 389 41 390 - 0) Linux driver version (this will change if format changes) 391 - 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. 392 - 2) APM flags from APM Installation Check (0x00): 393 - bit 0: APM_16_BIT_SUPPORT 394 - bit 1: APM_32_BIT_SUPPORT 395 - bit 2: APM_IDLE_SLOWS_CLOCK 396 - bit 3: APM_BIOS_DISABLED 397 - bit 4: APM_BIOS_DISENGAGED 398 - 3) AC line status 399 - 0x00: Off-line 400 - 0x01: On-line 401 - 0x02: On backup power (BIOS >= 1.1 only) 402 - 0xff: Unknown 403 - 4) Battery status 404 - 0x00: High 405 - 0x01: Low 406 - 0x02: Critical 407 - 0x03: Charging 408 - 0x04: Selected battery not present (BIOS >= 1.2 only) 409 - 0xff: Unknown 410 - 5) Battery flag 411 - bit 0: High 412 - bit 1: Low 413 - bit 2: Critical 414 - bit 3: Charging 415 - bit 7: No system battery 416 - 0xff: Unknown 417 - 6) Remaining battery life (percentage of charge): 418 - 0-100: valid 419 - -1: Unknown 420 - 7) Remaining battery life (time units): 421 - Number of remaining minutes or seconds 422 - -1: Unknown 423 - 8) min = minutes; sec = seconds */ 42 + info->battery_status = APM_BATTERY_STATUS_UNKNOWN; 43 + info->battery_flag = APM_BATTERY_FLAG_UNKNOWN; 44 + info->units = APM_UNITS_MINS; 424 45 425 - unsigned short ac_line_status; 426 - unsigned short battery_status = 0; 427 - unsigned short battery_flag = 0xff; 428 - int percentage = -1; 429 - int time_units = -1; 430 - int real_count = 0; 431 - int i; 432 - char * p = buf; 433 - char charging = 0; 434 - long charge = -1; 435 - long amperage = 0; 436 - unsigned long btype = 0; 46 + if (pmu_power_flags & PMU_PWR_AC_PRESENT) 47 + info->ac_line_status = APM_AC_ONLINE; 48 + else 49 + info->ac_line_status = APM_AC_OFFLINE; 437 50 438 - ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); 439 51 for (i=0; i<pmu_battery_count; i++) { 440 52 if (pmu_batteries[i].flags & PMU_BATT_PRESENT) { 441 - battery_status++; 53 + batteries++; 442 54 if (percentage < 0) 443 55 percentage = 0; 444 56 if (charge < 0) ··· 64 456 charging++; 65 457 } 66 458 } 67 - if (0 == battery_status) 68 - ac_line_status = 1; 69 - battery_status = 0xff; 459 + if (batteries == 0) 460 + info->ac_line_status = APM_AC_ONLINE; 461 + 70 462 if (real_count) { 71 463 if (amperage < 0) { 72 464 if (btype == PMU_BATT_TYPE_SMART) ··· 76 468 } 77 469 percentage /= real_count; 78 470 if (charging > 0) { 79 - battery_status = 0x03; 80 - battery_flag = 0x08; 471 + info->battery_status = APM_BATTERY_STATUS_CHARGING; 472 + info->battery_flag = APM_BATTERY_FLAG_CHARGING; 81 473 } else if (percentage <= APM_CRITICAL) { 82 - battery_status = 0x02; 83 - battery_flag = 0x04; 474 + info->battery_status = APM_BATTERY_STATUS_CRITICAL; 475 + info->battery_flag = APM_BATTERY_FLAG_CRITICAL; 84 476 } else if (percentage <= APM_LOW) { 85 - battery_status = 0x01; 86 - battery_flag = 0x02; 477 + info->battery_status = APM_BATTERY_STATUS_LOW; 478 + info->battery_flag = APM_BATTERY_FLAG_LOW; 87 479 } else { 88 - battery_status = 0x00; 89 - battery_flag = 0x01; 480 + info->battery_status = APM_BATTERY_STATUS_HIGH; 481 + info->battery_flag = APM_BATTERY_FLAG_HIGH; 90 482 } 91 483 } 92 - p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", 93 - driver_version, 94 - (FAKE_APM_BIOS_VERSION >> 8) & 0xff, 95 - FAKE_APM_BIOS_VERSION & 0xff, 96 - 0, 97 - ac_line_status, 98 - battery_status, 99 - battery_flag, 100 - percentage, 101 - time_units, 102 - "min"); 103 484 104 - return p - buf; 485 + info->battery_life = percentage; 486 + info->time = time_units; 105 487 } 106 - 107 - static const struct file_operations apm_bios_fops = { 108 - .owner = THIS_MODULE, 109 - .read = do_read, 110 - .poll = do_poll, 111 - .ioctl = do_ioctl, 112 - .open = do_open, 113 - .release = do_release, 114 - }; 115 - 116 - static struct miscdevice apm_device = { 117 - APM_MINOR_DEV, 118 - "apm_bios", 119 - &apm_bios_fops 120 - }; 121 488 122 489 static int __init apm_emu_init(void) 123 490 { 124 - struct proc_dir_entry *apm_proc; 491 + apm_get_power_status = pmu_apm_get_power_status; 125 492 126 - if (sys_ctrler != SYS_CTRLER_PMU) { 127 - printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n"); 128 - return -ENODEV; 129 - } 130 - 131 - apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info); 132 - if (apm_proc) 133 - apm_proc->owner = THIS_MODULE; 134 - 135 - if (misc_register(&apm_device) != 0) 136 - printk(KERN_INFO "Could not create misc. device for apm\n"); 137 - 138 - pmu_register_sleep_notifier(&apm_sleep_notifier); 139 - 140 - printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version); 493 + printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n"); 141 494 142 495 return 0; 143 496 } 144 497 145 498 static void __exit apm_emu_exit(void) 146 499 { 147 - pmu_unregister_sleep_notifier(&apm_sleep_notifier); 148 - misc_deregister(&apm_device); 149 - remove_proc_entry("apm", NULL); 500 + if (apm_get_power_status == pmu_apm_get_power_status) 501 + apm_get_power_status = NULL; 150 502 151 - printk(KERN_INFO "apm_emu: APM Emulation removed.\n"); 503 + printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n"); 152 504 } 153 505 154 506 module_init(apm_emu_init); 155 507 module_exit(apm_emu_exit); 156 508 157 509 MODULE_AUTHOR("Benjamin Herrenschmidt"); 158 - MODULE_DESCRIPTION("APM emulation layer for PowerMac"); 510 + MODULE_DESCRIPTION("APM emulation for PowerMac"); 159 511 MODULE_LICENSE("GPL"); 160 -