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 @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -76,6 +77,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(_kern_evdev, OID_AUTO, input, CTLFLAG_RD, 0, + "Evdev input devices"); #endif static void evdev_start_repeat(struct evdev_dev *, uint16_t); @@ -196,6 +199,166 @@ return (size); } +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 void +evdev_sysctl_create(struct evdev_dev *evdev) +{ + struct sysctl_oid *ev_sysctl_tree; + char ev_unit_str[8]; + + snprintf(ev_unit_str, sizeof(ev_unit_str), "%d", evdev->ev_unit); + sysctl_ctx_init(&evdev->ev_sysctl_ctx); + + ev_sysctl_tree = SYSCTL_ADD_NODE_WITH_LABEL(&evdev->ev_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_kern_evdev_input), OID_AUTO, + ev_unit_str, CTLFLAG_RD, NULL, "", "device index"); + + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "name", CTLFLAG_RD, + evdev->ev_name, strlen(evdev->ev_name), + "Input device name"); + + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "phys", CTLFLAG_RD, + evdev->ev_shortname, strlen(evdev->ev_shortname), + "Input device short name"); + + SYSCTL_ADD_STRING(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(ev_sysctl_tree), OID_AUTO, "uniq", CTLFLAG_RD, + evdev->ev_serial, strlen(evdev->ev_serial), + "Input device serial number"); + + SYSCTL_ADD_PROC(&evdev->ev_sysctl_ctx, + SYSCTL_CHILDREN(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(ev_sysctl_tree), OID_AUTO, "type_bits", + 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(ev_sysctl_tree), OID_AUTO, "key_bits", + 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(ev_sysctl_tree), OID_AUTO, "rel_bits", + 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(ev_sysctl_tree), OID_AUTO, "abs_bits", + 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(ev_sysctl_tree), OID_AUTO, "msc_bits", + 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(ev_sysctl_tree), OID_AUTO, "led_bits", + 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(ev_sysctl_tree), OID_AUTO, "snd_bits", + 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(ev_sysctl_tree), OID_AUTO, "sw_bits", + 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(ev_sysctl_tree), OID_AUTO, "props", + CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, + evdev, EV_MAX, evdev_sysctl_handler_bits, + "", "Input device properties"); +} + static int evdev_register_common(struct evdev_dev *evdev) { @@ -235,6 +398,12 @@ /* 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) */ + evdev_sysctl_create(evdev); + bail_out: return (ret); } @@ -282,6 +451,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,9 @@ const struct evdev_methods * ev_methods; void * ev_softc; + /* Sysctl: */ + struct sysctl_ctx_list ev_sysctl_ctx; + LIST_ENTRY(evdev_dev) ev_link; LIST_HEAD(, evdev_client) ev_clients; };