diff options
Diffstat (limited to 'sys/dev/asmc/asmc.c')
| -rw-r--r-- | sys/dev/asmc/asmc.c | 696 |
1 files changed, 487 insertions, 209 deletions
diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c index d99c1d56e67c..4a6734e22786 100644 --- a/sys/dev/asmc/asmc.c +++ b/sys/dev/asmc/asmc.c @@ -34,6 +34,8 @@ * Inspired by the Linux applesmc driver. */ +#include "opt_asmc.h" + #include <sys/param.h> #include <sys/bus.h> #include <sys/conf.h> @@ -49,12 +51,16 @@ #include <sys/rman.h> #include <machine/resource.h> +#include <netinet/in.h> #include <contrib/dev/acpica/include/acpi.h> #include <dev/acpica/acpivar.h> #include <dev/asmc/asmcvar.h> +#include <dev/backlight/backlight.h> +#include "backlight_if.h" + /* * Device interface. */ @@ -64,6 +70,15 @@ static int asmc_detach(device_t dev); static int asmc_resume(device_t dev); /* + * Backlight interface. + */ +static int asmc_backlight_update_status(device_t dev, + struct backlight_props *props); +static int asmc_backlight_get_status(device_t dev, + struct backlight_props *props); +static int asmc_backlight_get_info(device_t dev, struct backlight_info *info); + +/* * SMC functions. */ static int asmc_init(device_t dev); @@ -83,7 +98,7 @@ static void asmc_sms_calibrate(device_t dev); static int asmc_sms_intrfast(void *arg); static void asmc_sms_printintr(device_t dev, uint8_t); static void asmc_sms_task(void *arg, int pending); -#ifdef DEBUG +#ifdef ASMC_DEBUG void asmc_dumpall(device_t); static int asmc_key_dump(device_t, int); #endif @@ -97,6 +112,7 @@ static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS); +static int asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS); static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS); @@ -105,10 +121,11 @@ static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS); +static int asmc_wol_sysctl(SYSCTL_HANDLER_ARGS); struct asmc_model { - const char *smc_model; /* smbios.system.product env var. */ - const char *smc_desc; /* driver description */ + const char *smc_model; /* smbios.system.product env var. */ + const char *smc_desc; /* driver description */ /* Helper functions */ int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); @@ -131,48 +148,68 @@ struct asmc_model { static const struct asmc_model *asmc_match(device_t dev); -#define ASMC_SMS_FUNCS asmc_mb_sysctl_sms_x, asmc_mb_sysctl_sms_y, \ - asmc_mb_sysctl_sms_z - -#define ASMC_SMS_FUNCS_DISABLED NULL,NULL,NULL - -#define ASMC_FAN_FUNCS asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, asmc_mb_sysctl_fansafespeed, \ - asmc_mb_sysctl_fanminspeed, \ - asmc_mb_sysctl_fanmaxspeed, \ - asmc_mb_sysctl_fantargetspeed - -#define ASMC_FAN_FUNCS2 asmc_mb_sysctl_fanid, asmc_mb_sysctl_fanspeed, NULL, \ - asmc_mb_sysctl_fanminspeed, \ - asmc_mb_sysctl_fanmaxspeed, \ - asmc_mb_sysctl_fantargetspeed - -#define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \ - asmc_mbp_sysctl_light_right, \ - asmc_mbp_sysctl_light_control +#define ASMC_SMS_FUNCS \ + .smc_sms_x = asmc_mb_sysctl_sms_x, \ + .smc_sms_y = asmc_mb_sysctl_sms_y, \ + .smc_sms_z = asmc_mb_sysctl_sms_z + +#define ASMC_SMS_FUNCS_DISABLED \ + .smc_sms_x = NULL, \ + .smc_sms_y = NULL, \ + .smc_sms_z = NULL + +#define ASMC_FAN_FUNCS \ + .smc_fan_id = asmc_mb_sysctl_fanid, \ + .smc_fan_speed = asmc_mb_sysctl_fanspeed, \ + .smc_fan_safespeed = asmc_mb_sysctl_fansafespeed, \ + .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \ + .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \ + .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed + +#define ASMC_FAN_FUNCS2 \ + .smc_fan_id = asmc_mb_sysctl_fanid, \ + .smc_fan_speed = asmc_mb_sysctl_fanspeed, \ + .smc_fan_safespeed = NULL, \ + .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \ + .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \ + .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed + +#define ASMC_LIGHT_FUNCS \ + .smc_light_left = asmc_mbp_sysctl_light_left, \ + .smc_light_right = asmc_mbp_sysctl_light_right, \ + .smc_light_control = asmc_mbp_sysctl_light_control #define ASMC_LIGHT_FUNCS_10BYTE \ - asmc_mbp_sysctl_light_left_10byte, \ - NULL, \ - asmc_mbp_sysctl_light_control + .smc_light_left = asmc_mbp_sysctl_light_left_10byte, \ + .smc_light_right = NULL, \ + .smc_light_control = asmc_mbp_sysctl_light_control -#define ASMC_LIGHT_FUNCS_DISABLED NULL, NULL, NULL +#define ASMC_LIGHT_FUNCS_DISABLED \ + .smc_light_left = NULL, \ + .smc_light_right = NULL, \ + .smc_light_control = NULL + +#define ASMC_TEMPS_FUNCS_DISABLED \ + .smc_temps = {}, \ + .smc_tempnames = {}, \ + .smc_tempdescs = {} \ static const struct asmc_model asmc_models[] = { { "MacBook1,1", "Apple SMC MacBook Core Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS }, { "MacBook2,1", "Apple SMC MacBook Core 2 Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS }, { "MacBook3,1", "Apple SMC MacBook Core 2 Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS }, @@ -255,6 +292,12 @@ static const struct asmc_model asmc_models[] = { }, { + "MacBookPro8,3", "Apple SMC MacBook Pro (early 2011, 17-inch)", + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, + ASMC_MBP83_TEMPS, ASMC_MBP83_TEMPNAMES, ASMC_MBP83_TEMPDESCS + }, + + { "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)", ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS @@ -280,16 +323,23 @@ static const struct asmc_model asmc_models[] = { { "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS }, + { + "MacBookPro11,5", + "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch, AMD GPU)", + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, + ASMC_MBP115_TEMPS, ASMC_MBP115_TEMPNAMES, ASMC_MBP115_TEMPDESCS + }, + /* The Mac Mini has no SMS */ { "Macmini1,1", "Apple SMC Mac Mini", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS }, @@ -305,9 +355,9 @@ static const struct asmc_model asmc_models[] = { /* The Mac Mini 3,1 has no SMS */ { "Macmini3,1", "Apple SMC Mac Mini 3,1", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS }, @@ -315,7 +365,7 @@ static const struct asmc_model asmc_models[] = { { "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)", ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, + ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS }, @@ -324,18 +374,18 @@ static const struct asmc_model asmc_models[] = { /* - same sensors as Mac Mini 5,2 */ { "Macmini5,1", "Apple SMC Mac Mini 5,1", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS }, /* The Mac Mini 5,2 has no SMS */ { "Macmini5,2", "Apple SMC Mac Mini 5,2", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS }, @@ -343,63 +393,72 @@ static const struct asmc_model asmc_models[] = { /* - same sensors as Mac Mini 5,2 */ { "Macmini5,3", "Apple SMC Mac Mini 5,3", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS }, /* The Mac Mini 6,1 has no SMS */ { "Macmini6,1", "Apple SMC Mac Mini 6,1", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS }, /* The Mac Mini 6,2 has no SMS */ { "Macmini6,2", "Apple SMC Mac Mini 6,2", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS }, /* The Mac Mini 7,1 has no SMS */ { "Macmini7,1", "Apple SMC Mac Mini 7,1", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS }, /* Idem for the Mac Pro "Quad Core" (original) */ { "MacPro1,1", "Apple SMC Mac Pro (Quad Core)", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS }, + /* Idem for the Mac Pro (Early 2008) */ + { + "MacPro3,1", "Apple SMC Mac Pro (Early 2008)", + ASMC_SMS_FUNCS_DISABLED, + ASMC_FAN_FUNCS, + ASMC_LIGHT_FUNCS_DISABLED, + ASMC_MP31_TEMPS, ASMC_MP31_TEMPNAMES, ASMC_MP31_TEMPDESCS + }, + /* Idem for the Mac Pro (8-core) */ { "MacPro2", "Apple SMC Mac Pro (8-core)", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS }, /* Idem for the MacPro 2010*/ { "MacPro5,1", "Apple SMC MacPro (2010)", - NULL, NULL, NULL, + ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, - NULL, NULL, NULL, + ASMC_LIGHT_FUNCS_DISABLED, ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS }, @@ -414,20 +473,20 @@ static const struct asmc_model asmc_models[] = { { "MacBookAir1,1", "Apple SMC MacBook Air", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS }, { "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL, + ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS }, { "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)", ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, + ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS }, @@ -435,7 +494,7 @@ static const struct asmc_model asmc_models[] = { { "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)", ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, + ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS }, @@ -482,8 +541,42 @@ static const struct asmc_model asmc_models[] = { ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS + } +}; + +static const struct asmc_model asmc_generic_models[] = { + { + .smc_model = "MacBookAir", + .smc_desc = NULL, + ASMC_SMS_FUNCS_DISABLED, + ASMC_FAN_FUNCS2, + ASMC_LIGHT_FUNCS, + ASMC_TEMPS_FUNCS_DISABLED }, - { NULL, NULL } + { + .smc_model = "MacBookPro", + .smc_desc = NULL, + ASMC_SMS_FUNCS_DISABLED, + ASMC_FAN_FUNCS2, + ASMC_LIGHT_FUNCS, + ASMC_TEMPS_FUNCS_DISABLED + }, + { + .smc_model = "MacPro", + .smc_desc = NULL, + ASMC_SMS_FUNCS_DISABLED, + ASMC_FAN_FUNCS2, + ASMC_LIGHT_FUNCS_DISABLED, + ASMC_TEMPS_FUNCS_DISABLED + }, + { + .smc_model = "Macmini", + .smc_desc = NULL, + ASMC_SMS_FUNCS_DISABLED, + ASMC_FAN_FUNCS2, + ASMC_LIGHT_FUNCS_DISABLED, + ASMC_TEMPS_FUNCS_DISABLED + } }; #undef ASMC_SMS_FUNCS @@ -500,7 +593,13 @@ static device_method_t asmc_methods[] = { DEVMETHOD(device_attach, asmc_attach), DEVMETHOD(device_detach, asmc_detach), DEVMETHOD(device_resume, asmc_resume), - { 0, 0 } + + /* Backlight interface */ + DEVMETHOD(backlight_update_status, asmc_backlight_update_status), + DEVMETHOD(backlight_get_status, asmc_backlight_get_status), + DEVMETHOD(backlight_get_info, asmc_backlight_get_info), + + DEVMETHOD_END }; static driver_t asmc_driver = { @@ -514,10 +613,10 @@ static driver_t asmc_driver = { */ #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("ASMC") -#ifdef DEBUG -#define ASMC_DPRINTF(str) device_printf(dev, str) +#ifdef ASMC_DEBUG +#define ASMC_DPRINTF(str, ...) device_printf(dev, str, ##__VA_ARGS__) #else -#define ASMC_DPRINTF(str) +#define ASMC_DPRINTF(str, ...) #endif /* NB: can't be const */ @@ -525,34 +624,49 @@ static char *asmc_ids[] = { "APP0001", NULL }; static unsigned int light_control = 0; +ACPI_PNP_INFO(asmc_ids); DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL); MODULE_DEPEND(asmc, acpi, 1, 1, 1); +MODULE_DEPEND(asmc, backlight, 1, 1, 1); static const struct asmc_model * asmc_match(device_t dev) { + const struct asmc_model *model; + char *model_name; int i; - char *model; - model = kern_getenv("smbios.system.product"); - if (model == NULL) - return (NULL); + model = NULL; + + model_name = kern_getenv("smbios.system.product"); + if (model_name == NULL) + goto out; - for (i = 0; asmc_models[i].smc_model; i++) { - if (!strncmp(model, asmc_models[i].smc_model, strlen(model))) { - freeenv(model); - return (&asmc_models[i]); + for (i = 0; i < nitems(asmc_models); i++) { + if (strncmp(model_name, asmc_models[i].smc_model, + strlen(model_name)) == 0) { + model = &asmc_models[i]; + goto out; + } + } + for (i = 0; i < nitems(asmc_generic_models); i++) { + if (strncmp(model_name, asmc_generic_models[i].smc_model, + strlen(asmc_generic_models[i].smc_model)) == 0) { + model = &asmc_generic_models[i]; + goto out; } } - freeenv(model); - return (NULL); +out: + freeenv(model_name); + return (model); } static int asmc_probe(device_t dev) { const struct asmc_model *model; + const char *device_desc; int rv; if (resource_disabled("asmc", 0)) @@ -562,11 +676,13 @@ asmc_probe(device_t dev) return (rv); model = asmc_match(dev); - if (!model) { + if (model == NULL) { device_printf(dev, "model not recognized\n"); return (ENXIO); } - device_set_desc(dev, model->smc_desc); + device_desc = model->smc_desc == NULL ? + model->smc_model : model->smc_desc; + device_set_desc(dev, device_desc); return (rv); } @@ -589,7 +705,7 @@ asmc_attach(device_t dev) return (ENOMEM); } - sysctlctx = device_get_sysctl_ctx(dev); + sysctlctx = device_get_sysctl_ctx(dev); sysctlnode = device_get_sysctl_tree(dev); model = asmc_match(dev); @@ -611,51 +727,51 @@ asmc_attach(device_t dev) name[0] = '0' + j; name[1] = 0; sc->sc_fan_tree[i] = SYSCTL_ADD_NODE(sysctlctx, - SYSCTL_CHILDREN(sc->sc_fan_tree[0]), - OID_AUTO, name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, - "Fan Subtree"); + SYSCTL_CHILDREN(sc->sc_fan_tree[0]), OID_AUTO, name, + CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Fan Subtree"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "id", - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_id, "I", - "Fan ID"); + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_id, "I", "Fan ID"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "speed", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_speed, "I", - "Fan speed in RPM"); + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_speed, "I", "Fan speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "safespeed", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_safespeed, "I", - "Fan safe speed in RPM"); + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_safespeed, "I", "Fan safe speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "minspeed", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_minspeed, "I", - "Fan minimum speed in RPM"); + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_minspeed, "I", "Fan minimum speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "maxspeed", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_maxspeed, "I", - "Fan maximum speed in RPM"); + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_maxspeed, "I", "Fan maximum speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "targetspeed", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, - dev, j, model->smc_fan_targetspeed, "I", - "Fan target speed in RPM"); + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, + model->smc_fan_targetspeed, "I", "Fan target speed in RPM"); + + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sc->sc_fan_tree[i]), + OID_AUTO, "manual", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, + asmc_mb_sysctl_fanmanual, "I", + "Fan manual mode (0=auto, 1=manual)"); } /* @@ -669,8 +785,8 @@ asmc_attach(device_t dev) SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_temp_tree), OID_AUTO, model->smc_tempnames[i], - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - dev, i, asmc_temp_sysctl, "I", + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i, + asmc_temp_sysctl, "I", model->smc_tempdescs[i]); } @@ -686,24 +802,30 @@ asmc_attach(device_t dev) SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_light_tree), OID_AUTO, "left", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, model->smc_light_left, "I", "Keyboard backlight left sensor"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_light_tree), OID_AUTO, "right", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, - dev, 0, model->smc_light_right, "I", + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, + model->smc_light_right, "I", "Keyboard backlight right sensor"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_light_tree), OID_AUTO, "control", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | - CTLFLAG_NEEDGIANT, dev, 0, - model->smc_light_control, "I", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, + dev, 0, model->smc_light_control, "I", "Keyboard backlight brightness control"); + + sc->sc_kbd_bkl = backlight_register("asmc", dev); + if (sc->sc_kbd_bkl == NULL) { + device_printf(dev, "Can not register backlight\n"); + ret = ENXIO; + goto err; + } } if (model->smc_sms_x == NULL) @@ -719,21 +841,21 @@ asmc_attach(device_t dev) SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "x", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, model->smc_sms_x, "I", "Sudden Motion Sensor X value"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "y", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, model->smc_sms_y, "I", "Sudden Motion Sensor Y value"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "z", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, model->smc_sms_z, "I", "Sudden Motion Sensor Z value"); @@ -757,33 +879,26 @@ asmc_attach(device_t dev) * Allocate an IRQ for the SMS. */ sc->sc_rid_irq = 0; - sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, - &sc->sc_rid_irq, RF_ACTIVE); + sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_rid_irq, + RF_ACTIVE); if (sc->sc_irq == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); ret = ENXIO; - goto err2; + goto err; } - ret = bus_setup_intr(dev, sc->sc_irq, - INTR_TYPE_MISC | INTR_MPSAFE, - asmc_sms_intrfast, NULL, - dev, &sc->sc_cookie); - + ret = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, + asmc_sms_intrfast, NULL, dev, &sc->sc_cookie); if (ret) { device_printf(dev, "unable to setup SMS IRQ\n"); - goto err1; + goto err; } + nosms: return (0); -err1: - bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); -err2: - bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, - sc->sc_ioport); - mtx_destroy(&sc->sc_mtx); - if (sc->sc_sms_tq) - taskqueue_free(sc->sc_sms_tq); + +err: + asmc_detach(dev); return (ret); } @@ -793,19 +908,31 @@ asmc_detach(device_t dev) { struct asmc_softc *sc = device_get_softc(dev); + if (sc->sc_kbd_bkl != NULL) + backlight_destroy(sc->sc_kbd_bkl); + if (sc->sc_sms_tq) { taskqueue_drain(sc->sc_sms_tq, &sc->sc_sms_task); taskqueue_free(sc->sc_sms_tq); + sc->sc_sms_tq = NULL; } - if (sc->sc_cookie) + if (sc->sc_cookie) { bus_teardown_intr(dev, sc->sc_irq, sc->sc_cookie); - if (sc->sc_irq) + sc->sc_cookie = NULL; + } + if (sc->sc_irq) { bus_release_resource(dev, SYS_RES_IRQ, sc->sc_rid_irq, sc->sc_irq); - if (sc->sc_ioport) + sc->sc_irq = NULL; + } + if (sc->sc_ioport) { bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_rid_port, sc->sc_ioport); - mtx_destroy(&sc->sc_mtx); + sc->sc_ioport = NULL; + } + if (mtx_initialized(&sc->sc_mtx)) { + mtx_destroy(&sc->sc_mtx); + } return (0); } @@ -813,20 +940,29 @@ asmc_detach(device_t dev) static int asmc_resume(device_t dev) { - uint8_t buf[2]; - buf[0] = light_control; - buf[1] = 0x00; - asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); - return (0); + uint8_t buf[2]; + + buf[0] = light_control; + buf[1] = 0x00; + asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); + + return (0); } -#ifdef DEBUG -void asmc_dumpall(device_t dev) +#ifdef ASMC_DEBUG +void +asmc_dumpall(device_t dev) { + struct asmc_softc *sc = device_get_softc(dev); int i; - /* XXX magic number */ - for (i=0; i < 0x100; i++) + if (sc->sc_nkeys == 0) { + device_printf(dev, "asmc_dumpall: key count not available\n"); + return; + } + + device_printf(dev, "asmc_dumpall: dumping %d keys\n", sc->sc_nkeys); + for (i = 0; i < sc->sc_nkeys; i++) asmc_key_dump(dev, i); } #endif @@ -835,8 +971,17 @@ static int asmc_init(device_t dev) { struct asmc_softc *sc = device_get_softc(dev); + struct sysctl_ctx_list *sysctlctx; + uint8_t buf[6]; int i, error = 1; - uint8_t buf[4]; + + sysctlctx = device_get_sysctl_ctx(dev); + + error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6); + if (error != 0) + goto out_err; + device_printf(dev, "SMC revision: %x.%x%x%x\n", buf[0], buf[1], buf[2], + ntohs(*(uint16_t *)buf + 4)); if (sc->sc_model->smc_sms_x == NULL) goto nosms; @@ -907,25 +1052,40 @@ asmc_init(device_t dev) out: asmc_sms_calibrate(dev); nosms: + /* Wake-on-LAN convenience sysctl */ + if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) { + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "wol", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + dev, 0, asmc_wol_sysctl, "I", + "Wake-on-LAN enable (0=off, 1=on)"); + } + sc->sc_nfan = asmc_fan_count(dev); if (sc->sc_nfan > ASMC_MAXFANS) { - device_printf(dev, "more than %d fans were detected. Please " - "report this.\n", ASMC_MAXFANS); + device_printf(dev, + "more than %d fans were detected. Please report this.\n", + ASMC_MAXFANS); sc->sc_nfan = ASMC_MAXFANS; } - if (bootverbose) { - /* - * The number of keys is a 32 bit buffer - */ - asmc_key_read(dev, ASMC_NKEYS, buf, 4); - device_printf(dev, "number of keys: %d\n", ntohl(*(uint32_t*)buf)); + /* + * Read and cache the number of SMC keys (32 bit buffer) + */ + if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) { + sc->sc_nkeys = be32dec(buf); + if (bootverbose) + device_printf(dev, "number of keys: %d\n", + sc->sc_nkeys); + } else { + sc->sc_nkeys = 0; } -#ifdef DEBUG +out_err: +#ifdef ASMC_DEBUG asmc_dumpall(dev); #endif - return (error); } @@ -957,21 +1117,18 @@ asmc_wait_ack(device_t dev, uint8_t val, int amount) static int asmc_wait(device_t dev, uint8_t val) { -#ifdef DEBUG +#ifdef ASMC_DEBUG struct asmc_softc *sc; #endif if (asmc_wait_ack(dev, val, 1000) == 0) return (0); -#ifdef DEBUG +#ifdef ASMC_DEBUG sc = device_get_softc(dev); -#endif - val = val & ASMC_STATUS_MASK; -#ifdef DEBUG - device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val, - ASMC_CMDPORT_READ(sc)); + device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, + val & ASMC_STATUS_MASK, ASMC_CMDPORT_READ(sc)); #endif return (1); } @@ -981,18 +1138,19 @@ asmc_wait(device_t dev, uint8_t val) * the acknowledgement fails. */ static int -asmc_command(device_t dev, uint8_t command) { +asmc_command(device_t dev, uint8_t command) +{ int i; struct asmc_softc *sc = device_get_softc(dev); - for (i=0; i < 10; i++) { + for (i = 0; i < 10; i++) { ASMC_CMDPORT_WRITE(sc, command); if (asmc_wait_ack(dev, 0x0c, 100) == 0) { return (0); } } -#ifdef DEBUG +#ifdef ASMC_DEBUG device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command, ASMC_CMDPORT_READ(sc)); #endif @@ -1028,9 +1186,10 @@ begin: error = 0; out: if (error) { - if (++try < 10) goto begin; - device_printf(dev,"%s for key %s failed %d times, giving up\n", - __func__, key, try); + if (++try < 10) + goto begin; + device_printf(dev, "%s for key %s failed %d times, giving up\n", + __func__, key, try); } mtx_unlock_spin(&sc->sc_mtx); @@ -1038,7 +1197,7 @@ out: return (error); } -#ifdef DEBUG +#ifdef ASMC_DEBUG static int asmc_key_dump(device_t dev, int number) { @@ -1096,12 +1255,12 @@ begin: error = 0; out: if (error) { - if (++try < 10) goto begin; - device_printf(dev,"%s for key %s failed %d times, giving up\n", - __func__, key, try); + if (++try < 10) + goto begin; + device_printf(dev, "%s for key %s failed %d times, giving up\n", + __func__, key, try); mtx_unlock_spin(&sc->sc_mtx); - } - else { + } else { char buf[1024]; char buf2[8]; mtx_unlock_spin(&sc->sc_mtx); @@ -1110,16 +1269,17 @@ out: type[5] = 0; if (maxlen > sizeof(v)) { device_printf(dev, - "WARNING: cropping maxlen from %d to %zu\n", - maxlen, sizeof(v)); + "WARNING: cropping maxlen from %d to %zu\n", maxlen, + sizeof(v)); maxlen = sizeof(v); } for (i = 0; i < sizeof(v); i++) { v[i] = 0; } asmc_key_read(dev, key, v, maxlen); - snprintf(buf, sizeof(buf), "key %d is: %s, type %s " - "(len %d), data", number, key, type, maxlen); + snprintf(buf, sizeof(buf), + "key %d is: %s, type %s (len %d), data", + number, key, type, maxlen); for (i = 0; i < maxlen; i++) { snprintf(buf2, sizeof(buf2), " %02x", v[i]); strlcat(buf, buf2, sizeof(buf)); @@ -1164,15 +1324,15 @@ begin: error = 0; out: if (error) { - if (++try < 10) goto begin; - device_printf(dev,"%s for key %s failed %d times, giving up\n", - __func__, key, try); + if (++try < 10) + goto begin; + device_printf(dev, "%s for key %s failed %d times, giving up\n", + __func__, key, try); } mtx_unlock_spin(&sc->sc_mtx); return (error); - } /* @@ -1183,7 +1343,7 @@ asmc_fan_count(device_t dev) { uint8_t buf[1]; - if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof buf) != 0) + if (asmc_key_read(dev, ASMC_KEY_FANCOUNT, buf, sizeof(buf)) != 0) return (-1); return (buf[0]); @@ -1197,23 +1357,24 @@ asmc_fan_getvalue(device_t dev, const char *key, int fan) char fankey[5]; snprintf(fankey, sizeof(fankey), key, fan); - if (asmc_key_read(dev, fankey, buf, sizeof buf) != 0) + if (asmc_key_read(dev, fankey, buf, sizeof(buf)) != 0) return (-1); speed = (buf[0] << 6) | (buf[1] >> 2); return (speed); } -static char* -asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, uint8_t buflen) +static char * +asmc_fan_getstring(device_t dev, const char *key, int fan, uint8_t *buf, + uint8_t buflen) { char fankey[5]; - char* desc; + char *desc; snprintf(fankey, sizeof(fankey), key, fan); if (asmc_key_read(dev, fankey, buf, buflen) != 0) return (NULL); - desc = buf+4; + desc = buf + 4; return (desc); } @@ -1226,11 +1387,11 @@ asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) speed *= 4; - buf[0] = speed>>8; + buf[0] = speed >> 8; buf[1] = speed; snprintf(fankey, sizeof(fankey), key, fan); - if (asmc_key_write(dev, fankey, buf, sizeof buf) < 0) + if (asmc_key_write(dev, fankey, buf, sizeof(buf)) < 0) return (-1); return (0); @@ -1239,7 +1400,7 @@ asmc_fan_setvalue(device_t dev, const char *key, int fan, int speed) static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error; int32_t v; @@ -1254,10 +1415,10 @@ static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) { uint8_t buf[16]; - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error = true; - char* desc; + char *desc; desc = asmc_fan_getstring(dev, ASMC_KEY_FANID, fan, buf, sizeof(buf)); @@ -1270,7 +1431,7 @@ asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error; int32_t v; @@ -1284,7 +1445,7 @@ asmc_mb_sysctl_fansafespeed(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error; int32_t v; @@ -1303,7 +1464,7 @@ asmc_mb_sysctl_fanminspeed(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error; int32_t v; @@ -1322,7 +1483,7 @@ asmc_mb_sysctl_fanmaxspeed(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int fan = arg2; int error; int32_t v; @@ -1338,6 +1499,55 @@ asmc_mb_sysctl_fantargetspeed(SYSCTL_HANDLER_ARGS) return (error); } +static int +asmc_mb_sysctl_fanmanual(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + int fan = arg2; + int error; + int32_t v; + uint8_t buf[2]; + uint16_t val; + + /* Read current FS! bitmask (asmc_key_read locks internally) */ + error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, sizeof(buf)); + if (error != 0) + return (error); + + /* Extract manual bit for this fan (big-endian) */ + val = (buf[0] << 8) | buf[1]; + v = (val >> fan) & 0x01; + + /* Let sysctl handle the value */ + error = sysctl_handle_int(oidp, &v, 0, req); + + if (error == 0 && req->newptr != NULL) { + /* Validate input (0 = auto, 1 = manual) */ + if (v != 0 && v != 1) + return (EINVAL); + /* Read-modify-write of FS! bitmask */ + error = asmc_key_read(dev, ASMC_KEY_FANMANUAL, buf, + sizeof(buf)); + if (error == 0) { + val = (buf[0] << 8) | buf[1]; + + /* Modify single bit */ + if (v) + val |= (1 << fan); /* Set to manual */ + else + val &= ~(1 << fan); /* Set to auto */ + + /* Write back */ + buf[0] = val >> 8; + buf[1] = val & 0xff; + error = asmc_key_write(dev, ASMC_KEY_FANMANUAL, buf, + sizeof(buf)); + } + } + + return (error); +} + /* * Temperature functions. */ @@ -1349,7 +1559,7 @@ asmc_temp_getvalue(device_t dev, const char *key) /* * Check for invalid temperatures. */ - if (asmc_key_read(dev, key, buf, sizeof buf) != 0) + if (asmc_key_read(dev, key, buf, sizeof(buf)) != 0) return (-1); return (buf[0]); @@ -1358,7 +1568,7 @@ asmc_temp_getvalue(device_t dev, const char *key) static int asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; struct asmc_softc *sc = device_get_softc(dev); int error, val; @@ -1382,12 +1592,12 @@ asmc_sms_read(device_t dev, const char *key, int16_t *val) case 'X': case 'Y': case 'Z': - error = asmc_key_read(dev, key, buf, sizeof buf); + error = asmc_key_read(dev, key, buf, sizeof(buf)); break; default: device_printf(dev, "%s called with invalid argument %s\n", - __func__, key); - error = 1; + __func__, key); + error = EINVAL; goto out; } *val = ((int16_t)buf[0] << 8) | buf[1]; @@ -1409,7 +1619,7 @@ static int asmc_sms_intrfast(void *arg) { uint8_t type; - device_t dev = (device_t) arg; + device_t dev = (device_t)arg; struct asmc_softc *sc = device_get_softc(dev); if (!sc->sc_sms_intr_works) return (FILTER_HANDLED); @@ -1482,13 +1692,13 @@ asmc_sms_task(void *arg, int pending) static int asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int error; int16_t val; int32_t v; asmc_sms_read(dev, ASMC_KEY_SMS_X, &val); - v = (int32_t) val; + v = (int32_t)val; error = sysctl_handle_int(oidp, &v, 0, req); return (error); @@ -1497,13 +1707,13 @@ asmc_mb_sysctl_sms_x(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int error; int16_t val; int32_t v; asmc_sms_read(dev, ASMC_KEY_SMS_Y, &val); - v = (int32_t) val; + v = (int32_t)val; error = sysctl_handle_int(oidp, &v, 0, req); return (error); @@ -1512,13 +1722,13 @@ asmc_mb_sysctl_sms_y(SYSCTL_HANDLER_ARGS) static int asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; int error; int16_t val; int32_t v; asmc_sms_read(dev, ASMC_KEY_SMS_Z, &val); - v = (int32_t) val; + v = (int32_t)val; error = sysctl_handle_int(oidp, &v, 0, req); return (error); @@ -1527,12 +1737,12 @@ asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS) static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; uint8_t buf[6]; int error; int32_t v; - asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); + asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); v = buf[2]; error = sysctl_handle_int(oidp, &v, 0, req); @@ -1542,12 +1752,12 @@ asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS) static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; uint8_t buf[6]; int error; int32_t v; - asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof buf); + asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, sizeof(buf)); v = buf[2]; error = sysctl_handle_int(oidp, &v, 0, req); @@ -1557,7 +1767,8 @@ asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS) static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; + struct asmc_softc *sc = device_get_softc(dev); uint8_t buf[2]; int error; int v; @@ -1569,9 +1780,10 @@ asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) if (v < 0 || v > 255) return (EINVAL); light_control = v; + sc->sc_kbd_bkl_level = v * 100 / 255; buf[0] = light_control; buf[1] = 0x00; - asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof buf); + asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); } return (error); } @@ -1579,12 +1791,12 @@ asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS) static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) { - device_t dev = (device_t) arg1; + device_t dev = (device_t)arg1; uint8_t buf[10]; int error; uint32_t v; - asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof buf); + asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, sizeof(buf)); /* * This seems to be a 32 bit big endian value from buf[6] -> buf[9]. @@ -1605,3 +1817,69 @@ asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) return (error); } + +/* + * Wake-on-LAN convenience sysctl. + * Reading returns 1 if WoL is enabled, 0 if disabled. + * Writing 1 enables WoL, 0 disables it. + */ +static int +asmc_wol_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t)arg1; + uint8_t aupo; + int val, error; + + /* Read current AUPO value */ + if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) + return (EIO); + + val = (aupo != 0) ? 1 : 0; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || req->newptr == NULL) + return (error); + + /* Clamp to 0 or 1 */ + aupo = (val != 0) ? 1 : 0; + + /* Write AUPO */ + if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) + return (EIO); + + return (0); +} + +static int +asmc_backlight_update_status(device_t dev, struct backlight_props *props) +{ + struct asmc_softc *sc = device_get_softc(dev); + uint8_t buf[2]; + + sc->sc_kbd_bkl_level = props->brightness; + light_control = props->brightness * 255 / 100; + buf[0] = light_control; + buf[1] = 0x00; + asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, sizeof(buf)); + + return (0); +} + +static int +asmc_backlight_get_status(device_t dev, struct backlight_props *props) +{ + struct asmc_softc *sc = device_get_softc(dev); + + props->brightness = sc->sc_kbd_bkl_level; + props->nlevels = 0; + + return (0); +} + +static int +asmc_backlight_get_info(device_t dev, struct backlight_info *info) +{ + info->type = BACKLIGHT_TYPE_KEYBOARD; + strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH); + + return (0); +} |
