185556Siwasaki/*- 285556Siwasaki * Copyright (c) 2001 Mitsuru IWASAKI 385556Siwasaki * All rights reserved. 485556Siwasaki * 585556Siwasaki * Redistribution and use in source and binary forms, with or without 685556Siwasaki * modification, are permitted provided that the following conditions 785556Siwasaki * are met: 885556Siwasaki * 1. Redistributions of source code must retain the above copyright 985556Siwasaki * notice, this list of conditions and the following disclaimer. 1085556Siwasaki * 2. Redistributions in binary form must reproduce the above copyright 1185556Siwasaki * notice, this list of conditions and the following disclaimer in the 1285556Siwasaki * documentation and/or other materials provided with the distribution. 1385556Siwasaki * 1485556Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1585556Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1685556Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1785556Siwasaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1885556Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1985556Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2085556Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2185556Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2285556Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2385556Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2485556Siwasaki * SUCH DAMAGE. 2585556Siwasaki */ 2685556Siwasaki 27115681Sobrien#include <sys/cdefs.h> 28115681Sobrien__FBSDID("$FreeBSD$"); 29115681Sobrien 3085556Siwasaki#include <sys/param.h> 3185556Siwasaki#include <sys/bus.h> 32168191Sjhb#include <sys/condvar.h> 3385556Siwasaki#include <sys/conf.h> 3485556Siwasaki#include <sys/fcntl.h> 35215097Sjkim#include <sys/kernel.h> 36170976Snjl#include <sys/malloc.h> 37170976Snjl#include <sys/poll.h> 3885556Siwasaki#include <sys/uio.h> 3985556Siwasaki 40193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 41193530Sjkim 4285556Siwasaki#include <dev/acpica/acpivar.h> 4385556Siwasaki#include <dev/acpica/acpiio.h> 4485556Siwasaki 45215072Sjkim#include <machine/apm_bios.h> 46177157Sjhb 4785556Siwasaki/* 4885556Siwasaki * APM driver emulation 4985556Siwasaki */ 5085556Siwasaki 51215072Sjkim#define APM_UNKNOWN 0xff 5285556Siwasaki 53132619Snjlstatic int apm_active; 54170976Snjlstatic struct clonedevs *apm_clones; 5585556Siwasaki 56249132Smavstatic MALLOC_DEFINE(M_APMDEV, "apmdev", "APM device emulation"); 5785556Siwasaki 58170976Snjlstatic d_open_t apmopen; 59170976Snjlstatic d_close_t apmclose; 60170976Snjlstatic d_write_t apmwrite; 61170976Snjlstatic d_ioctl_t apmioctl; 62170976Snjlstatic d_poll_t apmpoll; 63170976Snjlstatic d_kqfilter_t apmkqfilter; 64170976Snjlstatic void apmreadfiltdetach(struct knote *kn); 65170976Snjlstatic int apmreadfilt(struct knote *kn, long hint); 66197134Srwatsonstatic struct filterops apm_readfiltops = { 67197134Srwatson .f_isfd = 1, 68197134Srwatson .f_detach = apmreadfiltdetach, 69197134Srwatson .f_event = apmreadfilt, 70197134Srwatson}; 71170976Snjl 7285556Siwasakistatic struct cdevsw apm_cdevsw = { 73126080Sphk .d_version = D_VERSION, 74179726Sed .d_flags = D_TRACKCLOSE | D_NEEDMINOR, 75111815Sphk .d_open = apmopen, 76111815Sphk .d_close = apmclose, 77111815Sphk .d_write = apmwrite, 78111815Sphk .d_ioctl = apmioctl, 79111815Sphk .d_poll = apmpoll, 80111815Sphk .d_name = "apm", 81170976Snjl .d_kqfilter = apmkqfilter 8285556Siwasaki}; 8385556Siwasaki 8485556Siwasakistatic int 8585556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 8685556Siwasaki{ 8785556Siwasaki int state; 8885556Siwasaki 89131218Simp state = APM_UNKNOWN; 9085556Siwasaki 9185556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 92119530Snjl if (battp->cap >= 50) 9385556Siwasaki state = 0; /* high */ 94119530Snjl else 9585556Siwasaki state = 1; /* low */ 9685556Siwasaki } 97119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 9885556Siwasaki state = 2; /* critical */ 99119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 10085556Siwasaki state = 3; /* charging */ 101119530Snjl 102120156Siwasaki /* If still unknown, determine it based on the battery capacity. */ 103131218Simp if (state == APM_UNKNOWN) { 104128975Snjl if (battp->cap >= 50) 105120156Siwasaki state = 0; /* high */ 106128975Snjl else 107120156Siwasaki state = 1; /* low */ 108120156Siwasaki } 109120156Siwasaki 11085556Siwasaki return (state); 11185556Siwasaki} 11285556Siwasaki 11385556Siwasakistatic int 11485556Siwasakiacpi_capm_convert_battflags(struct acpi_battinfo *battp) 11585556Siwasaki{ 11685556Siwasaki int flags; 11785556Siwasaki 11885556Siwasaki flags = 0; 11985556Siwasaki 120128975Snjl if (battp->cap >= 50) 12185556Siwasaki flags |= APM_BATT_HIGH; 122128975Snjl else { 123119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 12485556Siwasaki flags |= APM_BATT_CRITICAL; 125119530Snjl else 12685556Siwasaki flags |= APM_BATT_LOW; 12785556Siwasaki } 128119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 12985556Siwasaki flags |= APM_BATT_CHARGING; 130119530Snjl if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) 13185556Siwasaki flags = APM_BATT_NOT_PRESENT; 13285556Siwasaki 13385556Siwasaki return (flags); 13485556Siwasaki} 13585556Siwasaki 13685556Siwasakistatic int 13785556Siwasakiacpi_capm_get_info(apm_info_t aip) 13885556Siwasaki{ 13985556Siwasaki int acline; 14085556Siwasaki struct acpi_battinfo batt; 14185556Siwasaki 14285556Siwasaki aip->ai_infoversion = 1; 14385556Siwasaki aip->ai_major = 1; 14485556Siwasaki aip->ai_minor = 2; 145132619Snjl aip->ai_status = apm_active; 146131218Simp aip->ai_capabilities= 0xff00; /* unknown */ 14785556Siwasaki 148119530Snjl if (acpi_acad_get_acline(&acline)) 149131218Simp aip->ai_acline = APM_UNKNOWN; /* unknown */ 150119530Snjl else 15185556Siwasaki aip->ai_acline = acline; /* on/off */ 15285556Siwasaki 153148352Snjl if (acpi_battery_get_battinfo(NULL, &batt) != 0) { 154131218Simp aip->ai_batt_stat = APM_UNKNOWN; 155131218Simp aip->ai_batt_life = APM_UNKNOWN; 156131218Simp aip->ai_batt_time = -1; /* unknown */ 157131218Simp aip->ai_batteries = ~0U; /* unknown */ 15885556Siwasaki } else { 15985556Siwasaki aip->ai_batt_stat = acpi_capm_convert_battstate(&batt); 16085556Siwasaki aip->ai_batt_life = batt.cap; 16185556Siwasaki aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 16285556Siwasaki aip->ai_batteries = acpi_battery_get_units(); 16385556Siwasaki } 16485556Siwasaki 16585556Siwasaki return (0); 16685556Siwasaki} 16785556Siwasaki 16885556Siwasakistatic int 16985556Siwasakiacpi_capm_get_pwstatus(apm_pwstatus_t app) 17085556Siwasaki{ 171148352Snjl device_t dev; 172148352Snjl int acline, unit, error; 17385556Siwasaki struct acpi_battinfo batt; 17485556Siwasaki 17585556Siwasaki if (app->ap_device != PMDV_ALLDEV && 176128975Snjl (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) 17785556Siwasaki return (1); 17885556Siwasaki 179119530Snjl if (app->ap_device == PMDV_ALLDEV) 180148352Snjl error = acpi_battery_get_battinfo(NULL, &batt); 181148352Snjl else { 182148352Snjl unit = app->ap_device - PMDV_BATT0; 183148352Snjl dev = devclass_get_device(devclass_find("battery"), unit); 184148352Snjl if (dev != NULL) 185148352Snjl error = acpi_battery_get_battinfo(dev, &batt); 186148352Snjl else 187148352Snjl error = ENXIO; 188148352Snjl } 189148352Snjl if (error) 19085556Siwasaki return (1); 19185556Siwasaki 19285556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 19385556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 19485556Siwasaki app->ap_batt_life = batt.cap; 19585556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 19685556Siwasaki 197119530Snjl if (acpi_acad_get_acline(&acline)) 198131218Simp app->ap_acline = APM_UNKNOWN; 199119530Snjl else 20085556Siwasaki app->ap_acline = acline; /* on/off */ 20185556Siwasaki 20285556Siwasaki return (0); 20385556Siwasaki} 20485556Siwasaki 205170976Snjl/* Create single-use devices for /dev/apm and /dev/apmctl. */ 206170976Snjlstatic void 207170976Snjlapm_clone(void *arg, struct ucred *cred, char *name, int namelen, 208170976Snjl struct cdev **dev) 209170976Snjl{ 210170976Snjl int ctl_dev, unit; 211170976Snjl 212170976Snjl if (*dev != NULL) 213170976Snjl return; 214170976Snjl if (strcmp(name, "apmctl") == 0) 215170976Snjl ctl_dev = TRUE; 216170976Snjl else if (strcmp(name, "apm") == 0) 217170976Snjl ctl_dev = FALSE; 218170976Snjl else 219170976Snjl return; 220170976Snjl 221170976Snjl /* Always create a new device and unit number. */ 222170976Snjl unit = -1; 223170976Snjl if (clone_create(&apm_clones, &apm_cdevsw, &unit, dev, 0)) { 224170976Snjl if (ctl_dev) { 225183381Sed *dev = make_dev(&apm_cdevsw, unit, 226170976Snjl UID_ROOT, GID_OPERATOR, 0660, "apmctl%d", unit); 227170976Snjl } else { 228183381Sed *dev = make_dev(&apm_cdevsw, unit, 229170976Snjl UID_ROOT, GID_OPERATOR, 0664, "apm%d", unit); 230170976Snjl } 231170976Snjl if (*dev != NULL) { 232170976Snjl dev_ref(*dev); 233170976Snjl (*dev)->si_flags |= SI_CHEAPCLONE; 234170976Snjl } 235170976Snjl } 236170976Snjl} 237170976Snjl 238170976Snjl/* Create a struct for tracking per-device suspend notification. */ 239170976Snjlstatic struct apm_clone_data * 240170976Snjlapm_create_clone(struct cdev *dev, struct acpi_softc *acpi_sc) 241170976Snjl{ 242170976Snjl struct apm_clone_data *clone; 243170976Snjl 244170976Snjl clone = malloc(sizeof(*clone), M_APMDEV, M_WAITOK); 245170976Snjl clone->cdev = dev; 246170976Snjl clone->acpi_sc = acpi_sc; 247170976Snjl clone->notify_status = APM_EV_NONE; 248170976Snjl bzero(&clone->sel_read, sizeof(clone->sel_read)); 249193951Skib knlist_init_mtx(&clone->sel_read.si_note, &acpi_mutex); 250170976Snjl 251170976Snjl /* 252170976Snjl * The acpi device is always managed by devd(8) and is considered 253170976Snjl * writable (i.e., ack is required to allow suspend to proceed.) 254170976Snjl */ 255170976Snjl if (strcmp("acpi", devtoname(dev)) == 0) 256170976Snjl clone->flags = ACPI_EVF_DEVD | ACPI_EVF_WRITE; 257170976Snjl else 258170976Snjl clone->flags = ACPI_EVF_NONE; 259170976Snjl 260170976Snjl ACPI_LOCK(acpi); 261170976Snjl STAILQ_INSERT_TAIL(&acpi_sc->apm_cdevs, clone, entries); 262170976Snjl ACPI_UNLOCK(acpi); 263170976Snjl return (clone); 264170976Snjl} 265170976Snjl 26685556Siwasakistatic int 267192442Simpapmopen(struct cdev *dev, int flag, int fmt, struct thread *td) 26885556Siwasaki{ 269170976Snjl struct acpi_softc *acpi_sc; 270170976Snjl struct apm_clone_data *clone; 271170976Snjl 272170976Snjl acpi_sc = devclass_get_softc(devclass_find("acpi"), 0); 273170976Snjl clone = apm_create_clone(dev, acpi_sc); 274170976Snjl dev->si_drv1 = clone; 275170976Snjl 276170976Snjl /* If the device is opened for write, record that. */ 277170976Snjl if ((flag & FWRITE) != 0) 278170976Snjl clone->flags |= ACPI_EVF_WRITE; 279170976Snjl 28085556Siwasaki return (0); 28185556Siwasaki} 28285556Siwasaki 28385556Siwasakistatic int 284192442Simpapmclose(struct cdev *dev, int flag, int fmt, struct thread *td) 28585556Siwasaki{ 286170976Snjl struct apm_clone_data *clone; 287170976Snjl struct acpi_softc *acpi_sc; 288170976Snjl 289170976Snjl clone = dev->si_drv1; 290170976Snjl acpi_sc = clone->acpi_sc; 291170976Snjl 292170976Snjl /* We are about to lose a reference so check if suspend should occur */ 293170976Snjl if (acpi_sc->acpi_next_sstate != 0 && 294170976Snjl clone->notify_status != APM_EV_ACKED) 295170976Snjl acpi_AckSleepState(clone, 0); 296170976Snjl 297170976Snjl /* Remove this clone's data from the list and free it. */ 298170976Snjl ACPI_LOCK(acpi); 299170976Snjl STAILQ_REMOVE(&acpi_sc->apm_cdevs, clone, apm_clone_data, entries); 300225177Sattilio seldrain(&clone->sel_read); 301170976Snjl knlist_destroy(&clone->sel_read.si_note); 302170976Snjl ACPI_UNLOCK(acpi); 303170976Snjl free(clone, M_APMDEV); 304171297Snjl destroy_dev_sched(dev); 30585556Siwasaki return (0); 30685556Siwasaki} 30785556Siwasaki 30885556Siwasakistatic int 309192442Simpapmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 31085556Siwasaki{ 311170976Snjl int error; 312170976Snjl struct apm_clone_data *clone; 31385556Siwasaki struct acpi_softc *acpi_sc; 314170976Snjl struct apm_info info; 315170976Snjl struct apm_event_info *ev_info; 31685556Siwasaki apm_info_old_t aiop; 31785556Siwasaki 318170976Snjl error = 0; 319170976Snjl clone = dev->si_drv1; 320170976Snjl acpi_sc = clone->acpi_sc; 32185556Siwasaki 32285556Siwasaki switch (cmd) { 32385556Siwasaki case APMIO_SUSPEND: 324119530Snjl if ((flag & FWRITE) == 0) 32585556Siwasaki return (EPERM); 326170976Snjl if (acpi_sc->acpi_next_sstate == 0) { 327170976Snjl if (acpi_sc->acpi_suspend_sx != ACPI_STATE_S5) { 328170976Snjl error = acpi_ReqSleepState(acpi_sc, 329170976Snjl acpi_sc->acpi_suspend_sx); 330170976Snjl } else { 331170976Snjl printf( 332170976Snjl "power off via apm suspend not supported\n"); 333170976Snjl error = ENXIO; 334170976Snjl } 335170976Snjl } else 336170976Snjl error = acpi_AckSleepState(clone, 0); 33785556Siwasaki break; 33885556Siwasaki case APMIO_STANDBY: 339119530Snjl if ((flag & FWRITE) == 0) 34085556Siwasaki return (EPERM); 341170976Snjl if (acpi_sc->acpi_next_sstate == 0) { 342170976Snjl if (acpi_sc->acpi_standby_sx != ACPI_STATE_S5) { 343170976Snjl error = acpi_ReqSleepState(acpi_sc, 344170976Snjl acpi_sc->acpi_standby_sx); 345170976Snjl } else { 346170976Snjl printf( 347170976Snjl "power off via apm standby not supported\n"); 348170976Snjl error = ENXIO; 349170976Snjl } 350170976Snjl } else 351170976Snjl error = acpi_AckSleepState(clone, 0); 35285556Siwasaki break; 353170976Snjl case APMIO_NEXTEVENT: 354170976Snjl printf("apm nextevent start\n"); 355170976Snjl ACPI_LOCK(acpi); 356170976Snjl if (acpi_sc->acpi_next_sstate != 0 && clone->notify_status == 357170976Snjl APM_EV_NONE) { 358170976Snjl ev_info = (struct apm_event_info *)addr; 359170976Snjl if (acpi_sc->acpi_next_sstate <= ACPI_STATE_S3) 360170976Snjl ev_info->type = PMEV_STANDBYREQ; 361170976Snjl else 362170976Snjl ev_info->type = PMEV_SUSPENDREQ; 363170976Snjl ev_info->index = 0; 364170976Snjl clone->notify_status = APM_EV_NOTIFIED; 365170976Snjl printf("apm event returning %d\n", ev_info->type); 366170976Snjl } else 367170976Snjl error = EAGAIN; 368170976Snjl ACPI_UNLOCK(acpi); 369170976Snjl break; 37085556Siwasaki case APMIO_GETINFO_OLD: 37185556Siwasaki if (acpi_capm_get_info(&info)) 37285556Siwasaki error = ENXIO; 37385556Siwasaki aiop = (apm_info_old_t)addr; 37485556Siwasaki aiop->ai_major = info.ai_major; 37585556Siwasaki aiop->ai_minor = info.ai_minor; 37685556Siwasaki aiop->ai_acline = info.ai_acline; 37785556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 37885556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 37985556Siwasaki aiop->ai_status = info.ai_status; 38085556Siwasaki break; 38185556Siwasaki case APMIO_GETINFO: 38285556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 38385556Siwasaki error = ENXIO; 38485556Siwasaki break; 38585556Siwasaki case APMIO_GETPWSTATUS: 38685556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 38785556Siwasaki error = ENXIO; 38885556Siwasaki break; 38985556Siwasaki case APMIO_ENABLE: 390119530Snjl if ((flag & FWRITE) == 0) 39185556Siwasaki return (EPERM); 392132619Snjl apm_active = 1; 39385556Siwasaki break; 39485556Siwasaki case APMIO_DISABLE: 395119530Snjl if ((flag & FWRITE) == 0) 39685556Siwasaki return (EPERM); 397132619Snjl apm_active = 0; 39885556Siwasaki break; 39985556Siwasaki case APMIO_HALTCPU: 40085556Siwasaki break; 40185556Siwasaki case APMIO_NOTHALTCPU: 40285556Siwasaki break; 40385556Siwasaki case APMIO_DISPLAY: 404119530Snjl if ((flag & FWRITE) == 0) 40585556Siwasaki return (EPERM); 40685556Siwasaki break; 40785556Siwasaki case APMIO_BIOS: 408119530Snjl if ((flag & FWRITE) == 0) 40985556Siwasaki return (EPERM); 41085556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 41185556Siwasaki break; 41285556Siwasaki default: 41385556Siwasaki error = EINVAL; 41485556Siwasaki break; 41585556Siwasaki } 41685556Siwasaki 41785556Siwasaki return (error); 41885556Siwasaki} 41985556Siwasaki 42085556Siwasakistatic int 421130585Sphkapmwrite(struct cdev *dev, struct uio *uio, int ioflag) 42285556Siwasaki{ 42385556Siwasaki return (uio->uio_resid); 42485556Siwasaki} 42585556Siwasaki 42685556Siwasakistatic int 427192442Simpapmpoll(struct cdev *dev, int events, struct thread *td) 42885556Siwasaki{ 429170976Snjl struct apm_clone_data *clone; 430170976Snjl int revents; 431170976Snjl 432170976Snjl revents = 0; 433170976Snjl ACPI_LOCK(acpi); 434170976Snjl clone = dev->si_drv1; 435170976Snjl if (clone->acpi_sc->acpi_next_sstate) 436170976Snjl revents |= events & (POLLIN | POLLRDNORM); 437170976Snjl else 438170976Snjl selrecord(td, &clone->sel_read); 439170976Snjl ACPI_UNLOCK(acpi); 440170976Snjl return (revents); 441170976Snjl} 442170976Snjl 443170976Snjlstatic int 444170976Snjlapmkqfilter(struct cdev *dev, struct knote *kn) 445170976Snjl{ 446170976Snjl struct apm_clone_data *clone; 447170976Snjl 448170976Snjl ACPI_LOCK(acpi); 449170976Snjl clone = dev->si_drv1; 450170976Snjl kn->kn_hook = clone; 451170976Snjl kn->kn_fop = &apm_readfiltops; 452170976Snjl knlist_add(&clone->sel_read.si_note, kn, 0); 453170976Snjl ACPI_UNLOCK(acpi); 45485556Siwasaki return (0); 45585556Siwasaki} 45685556Siwasaki 45785556Siwasakistatic void 458170976Snjlapmreadfiltdetach(struct knote *kn) 45985556Siwasaki{ 460170976Snjl struct apm_clone_data *clone; 461170976Snjl 462170976Snjl ACPI_LOCK(acpi); 463170976Snjl clone = kn->kn_hook; 464170976Snjl knlist_remove(&clone->sel_read.si_note, kn, 0); 465170976Snjl ACPI_UNLOCK(acpi); 46685556Siwasaki} 46785556Siwasaki 468170976Snjlstatic int 469170976Snjlapmreadfilt(struct knote *kn, long hint) 470170976Snjl{ 471170976Snjl struct apm_clone_data *clone; 472170976Snjl int sleeping; 473170976Snjl 474170976Snjl ACPI_LOCK(acpi); 475170976Snjl clone = kn->kn_hook; 476170976Snjl sleeping = clone->acpi_sc->acpi_next_sstate ? 1 : 0; 477170976Snjl ACPI_UNLOCK(acpi); 478170976Snjl return (sleeping); 479170976Snjl} 480170976Snjl 481215097Sjkimvoid 482215097Sjkimacpi_apm_init(struct acpi_softc *sc) 48385556Siwasaki{ 48485556Siwasaki 485215097Sjkim /* Create a clone for /dev/acpi also. */ 486215097Sjkim STAILQ_INIT(&sc->apm_cdevs); 487215097Sjkim sc->acpi_clone = apm_create_clone(sc->acpi_dev_t, sc); 488170976Snjl clone_setup(&apm_clones); 489170976Snjl EVENTHANDLER_REGISTER(dev_clone, apm_clone, 0, 1000); 49085556Siwasaki} 491