Index: sys/dev/kbd/kbd.c =================================================================== --- sys/dev/kbd/kbd.c +++ sys/dev/kbd/kbd.c @@ -70,7 +70,7 @@ static SLIST_HEAD(, keyboard_driver) keyboard_drivers = SLIST_HEAD_INITIALIZER(keyboard_drivers); -SET_DECLARE(kbddriver_set, const keyboard_driver_t); +SET_DECLARE(kbddriver_set, keyboard_driver_t); /* local arrays */ @@ -163,12 +163,42 @@ int kbd_add_driver(keyboard_driver_t *driver) { - if (SLIST_NEXT(driver, link)) + keyboard_driver_t *p; + + if (driver->registered != 0) return (EINVAL); + + SLIST_FOREACH(p, &keyboard_drivers, link) { + KASSERT (strcmp(p->name, driver->name) != 0 || p == driver, + ("%s: duplicate keyboard_driver definitions for '%s'", + __func__, driver->name)); + if (p == driver) { + /* + * registered here indicates that we've invoked + * kbd_add_driver() on the driver previously. For + * drivers registered from the linker set, we don't + * consider it fully registered unless kbd_add_driver() + * is invoked on it because some of them are available + * with kld module events that will get triggered and + * cause us to register it. + */ + if (!p->registered) { + driver->registered = 1; + return (0); + } + + return (EINVAL); + } + } + + KASSERT(SLIST_NEXT(driver, link) == NULL, + ("%s: keyboard driver list garbage detected", __func__)); + driver->registered = 1; if (driver->kbdsw->get_fkeystr == NULL) driver->kbdsw->get_fkeystr = genkbd_get_fkeystr; if (driver->kbdsw->diag == NULL) driver->kbdsw->diag = genkbd_diag; + SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); return (0); } @@ -176,6 +206,12 @@ int kbd_delete_driver(keyboard_driver_t *driver) { + + /* Imbalanced kbd_add_driver/kbd_delete_driver. */ + if (!driver->registered) + return (EINVAL); + + driver->registered = 0; SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); SLIST_NEXT(driver, link) = NULL; return (0); @@ -185,7 +221,6 @@ int kbd_register(keyboard_t *kbd) { - const keyboard_driver_t **list; const keyboard_driver_t *p; keyboard_t *mux; keyboard_info_t ki; @@ -226,23 +261,6 @@ return (index); } } - SET_FOREACH(list, kbddriver_set) { - p = *list; - if (strcmp(p->name, kbd->kb_name) == 0) { - kbd->kb_drv = p; - keyboard[index] = kbd; - - if (mux != NULL) { - bzero(&ki, sizeof(ki)); - strcpy(ki.kb_name, kbd->kb_name); - ki.kb_unit = kbd->kb_unit; - - (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); - } - - return (index); - } - } return (-1); } @@ -282,18 +300,12 @@ keyboard_switch_t * kbd_get_switch(char *driver) { - const keyboard_driver_t **list; const keyboard_driver_t *p; SLIST_FOREACH(p, &keyboard_drivers, link) { if (strcmp(p->name, driver) == 0) return (p->kbdsw); } - SET_FOREACH(list, kbddriver_set) { - p = *list; - if (strcmp(p->name, driver) == 0) - return (p->kbdsw); - } return (NULL); } @@ -435,18 +447,12 @@ int kbd_configure(int flags) { - const keyboard_driver_t **list; const keyboard_driver_t *p; SLIST_FOREACH(p, &keyboard_drivers, link) { if (p->configure != NULL) (*p->configure)(flags); } - SET_FOREACH(list, kbddriver_set) { - p = *list; - if (p->configure != NULL) - (*p->configure)(flags); - } return (0); } @@ -1510,16 +1516,19 @@ static void kbd_drv_init(void) { - const keyboard_driver_t **list; - const keyboard_driver_t *p; + keyboard_driver_t *drv, **list; SET_FOREACH(list, kbddriver_set) { - p = *list; - if (p->kbdsw->get_fkeystr == NULL) - p->kbdsw->get_fkeystr = genkbd_get_fkeystr; - if (p->kbdsw->diag == NULL) - p->kbdsw->diag = genkbd_diag; + drv = *list; + + if (kbd_add_driver(drv) != 0) + printf("kbd: failed to register driver '%s'\n", + drv->name); + else if (bootverbose) + printf("kbd: registered driver '%s'\n", + drv->name); } + } SYSINIT(kbd_drv_init, SI_SUB_DRIVERS, SI_ORDER_FIRST, kbd_drv_init, NULL); Index: sys/dev/kbd/kbdreg.h =================================================================== --- sys/dev/kbd/kbdreg.h +++ sys/dev/kbd/kbdreg.h @@ -102,6 +102,7 @@ char *name; keyboard_switch_t *kbdsw; int (*configure)(int); /* backdoor for the console driver */ + int registered; } keyboard_driver_t; /* keyboard */