Index: sbin/sysctl/sysctl.c =================================================================== --- sbin/sysctl/sysctl.c +++ sbin/sysctl/sysctl.c @@ -49,6 +49,7 @@ #include #include #include +#include #ifdef __amd64__ #include @@ -680,6 +681,21 @@ return (0); } +static int +S_input_id(size_t l2, void *p) +{ + struct input_id *id = (struct input_id*)p; + + if (l2 != sizeof(*id)) { + warnx("S_input_id %zu != %zu", l2, sizeof(*id)); + return (1); + } + + printf("{ bustype = 0x%04x, vendor = 0x%04x, product = 0x%04x, version = 0x%04x }", + id->bustype, id->vendor, id->product, id->version); + return (0); +} + #ifdef __amd64__ static int S_efi_map(size_t l2, void *p) @@ -983,6 +999,8 @@ func = S_loadavg; else if (strcmp(fmt, "S,vmtotal") == 0) func = S_vmtotal; + else if (strcmp(fmt, "S,input_id") == 0) + func = S_input_id; #ifdef __amd64__ else if (strcmp(fmt, "S,efi_map_header") == 0) func = S_efi_map; Index: sys/dev/evdev/evdev.c =================================================================== --- sys/dev/evdev/evdev.c +++ sys/dev/evdev/evdev.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -76,6 +78,8 @@ "bit2 - mouse hardware, bit3 - keyboard hardware"); SYSCTL_INT(_kern_evdev, OID_AUTO, sysmouse_t_axis, CTLFLAG_RW, &evdev_sysmouse_t_axis, 0, "Extract T-axis from 0-none, 1-ums, 2-psm"); +SYSCTL_NODE(_dev, OID_AUTO, input, CTLFLAG_RD, 0, + "Evdev input devices"); #endif static void evdev_start_repeat(struct evdev_dev *, uint16_t); @@ -196,6 +200,145 @@ return (size); } +static void +evdev_notify_addq(const char *type, struct evdev_dev *evdev) +{ + struct sbuf *sb; + + sb = sbuf_new_auto(); + sbuf_printf(sb, + "cdev=%s " + "unit=%d " + "name=\"%s\" " + "shortname=%s " + "bustype=0x%04x " + "vendor=0x%04x " + "product=0x%04x " + "version=0x%04x ", + evdev->ev_cdev->si_name, + evdev->ev_unit, + evdev->ev_name, + evdev->ev_shortname, + evdev->ev_id.bustype, + evdev->ev_id.vendor, + evdev->ev_id.product, + evdev->ev_id.version + ); + sbuf_finish(sb); + devctl_notify("EVDEV", "DEVICE", type, sbuf_data(sb)); + sbuf_delete(sb); +} + +static int +evdev_sysctl_handler_name(SYSCTL_HANDLER_ARGS) +{ + struct evdev_dev *evdev = arg1; + int err; + + EVDEV_LOCK(evdev); + err = SYSCTL_OUT(req, evdev->ev_name, strlen(evdev->ev_name)); + EVDEV_UNLOCK(evdev); + + return (err); +} + +static int +evdev_sysctl_handler_shortname(SYSCTL_HANDLER_ARGS) +{ + struct evdev_dev *evdev = arg1; + int err; + + EVDEV_LOCK(evdev); + err = SYSCTL_OUT(req, evdev->ev_shortname, strlen(evdev->ev_shortname)); + EVDEV_UNLOCK(evdev); + + return (err); +} + +static int +evdev_sysctl_handler_serial(SYSCTL_HANDLER_ARGS) +{ + struct evdev_dev *evdev = arg1; + int err; + + EVDEV_LOCK(evdev); + err = SYSCTL_OUT(req, evdev->ev_serial, strlen(evdev->ev_serial)); + EVDEV_UNLOCK(evdev); + + return (err); +} + +static int +evdev_sysctl_handler_input_id(SYSCTL_HANDLER_ARGS) +{ + struct evdev_dev *evdev = arg1; + int err; + + EVDEV_LOCK(evdev); + err = SYSCTL_OUT(req, &evdev->ev_id, sizeof(struct input_id)); + EVDEV_UNLOCK(evdev); + + return (err); +} + +static int +evdev_sysctl_handler_bits(SYSCTL_HANDLER_ARGS) +{ + struct evdev_dev *evdev = arg1; + unsigned long *bitmap; + int err, limit; + + EVDEV_LOCK(evdev); + switch (arg2) { + case 0: + bitmap = evdev->ev_type_flags; + limit = EV_CNT; + break; + case EV_KEY: + bitmap = evdev->ev_key_flags; + limit = KEY_CNT; + break; + case EV_REL: + bitmap = evdev->ev_rel_flags; + limit = REL_CNT; + break; + case EV_ABS: + bitmap = evdev->ev_abs_flags; + limit = ABS_CNT; + break; + case EV_MSC: + bitmap = evdev->ev_msc_flags; + limit = MSC_CNT; + break; + case EV_LED: + bitmap = evdev->ev_led_flags; + limit = LED_CNT; + break; + case EV_SND: + bitmap = evdev->ev_snd_flags; + limit = SND_CNT; + break; + case EV_SW: + bitmap = evdev->ev_sw_flags; + limit = SW_CNT; + break; + case EV_MAX: + bitmap = evdev->ev_prop_flags; + limit = INPUT_PROP_CNT; + break; + case EV_FF: + /* + * We don't support EV_FF now. + */ + default: + return (ENOTTY); + } + err = SYSCTL_OUT(req, bitmap, bitstr_size(limit)); + EVDEV_UNLOCK(evdev); + + return (err); +} + static int evdev_register_common(struct evdev_dev *evdev) { @@ -235,6 +378,96 @@ /* Create char device node */ ret = evdev_cdev_create(evdev); + if (ret != 0) + goto bail_out; + + /* Create sysctls (for device enumeration without /dev/input access rights) */ + snprintf(evdev->ev_unit_str, sizeof(evdev->ev_unit_str), "%d", evdev->ev_unit); + sysctl_ctx_init(&evdev->ev_sysctl_ctx); + evdev->ev_sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&evdev->ev_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_dev_input), OID_AUTO, + evdev->ev_unit_str, CTLFLAG_RD, NULL, "", "device index"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "name", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, 0, evdev_sysctl_handler_name, + "", "Input device name"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "shortname", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, 0, evdev_sysctl_handler_shortname, + "", "Input device short name"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "serial", + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, 0, evdev_sysctl_handler_serial, + "", "Input device serial number"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "input_id", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, 0, evdev_sysctl_handler_input_id, + "S,input_id", "Input device identification"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "type_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, 0, evdev_sysctl_handler_bits, + "", "Input device supported events types"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "key_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_KEY, evdev_sysctl_handler_bits, + "", "Input device supported keys"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "rel_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_REL, evdev_sysctl_handler_bits, + "", "Input device supported relative events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "abs_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_ABS, evdev_sysctl_handler_bits, + "", "Input device supported absolute events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "msc_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_MSC, evdev_sysctl_handler_bits, + "", "Input device supported miscellaneous events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "led_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_LED, evdev_sysctl_handler_bits, + "", "Input device supported LED events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "snd_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_SND, evdev_sysctl_handler_bits, + "", "Input device supported sound events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "sw_flags", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_SW, evdev_sysctl_handler_bits, + "", "Input device supported switch events"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(evdev->ev_sysctl_tree), OID_AUTO, "props", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_MAX, evdev_sysctl_handler_bits, + "", "Input device properties"); + + /* Notify userspace with device details via devctl */ + evdev_notify_addq("ATTACH", evdev); bail_out: return (ret); } @@ -269,6 +502,7 @@ { struct evdev_client *client; int ret; + evdev_notify_addq("DETACH", evdev); debugf(evdev, "%s: unregistered evdev provider: %s\n", evdev->ev_shortname, evdev->ev_name); @@ -282,6 +516,7 @@ evdev_notify_event(client); EVDEV_CLIENT_UNLOCKQ(client); } + sysctl_ctx_free(&evdev->ev_sysctl_ctx); EVDEV_UNLOCK(evdev); /* destroy_dev can sleep so release lock */ Index: sys/dev/evdev/evdev_private.h =================================================================== --- sys/dev/evdev/evdev_private.h +++ sys/dev/evdev/evdev_private.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -132,6 +133,11 @@ const struct evdev_methods * ev_methods; void * ev_softc; + /* Sysctl: */ + char ev_unit_str[8]; + struct sysctl_ctx_list ev_sysctl_ctx; + struct sysctl_oid * ev_sysctl_tree; + LIST_ENTRY(evdev_dev) ev_link; LIST_HEAD(, evdev_client) ev_clients; };