diff --git a/sys/dev/gpio/gpioc.c b/sys/dev/gpio/gpioc.c --- a/sys/dev/gpio/gpioc.c +++ b/sys/dev/gpio/gpioc.c @@ -908,27 +908,38 @@ res = devfs_get_cdevpriv((void **)&priv); if (res != 0) break; + mtx_lock(&priv->mtx); /* If any pins have been configured, changes aren't allowed. */ if (!SLIST_EMPTY(&priv->pins)) { res = EINVAL; + mtx_unlock(&priv->mtx); break; } if (evcfg->gp_report_type != GPIO_EVENT_REPORT_DETAIL && evcfg->gp_report_type != GPIO_EVENT_REPORT_SUMMARY) { res = EINVAL; + mtx_unlock(&priv->mtx); break; } - priv->report_option = evcfg->gp_report_type; /* Reallocate the events buffer if the user wants it bigger. */ - if (priv->report_option == GPIO_EVENT_REPORT_DETAIL && + if (evcfg->gp_report_type == GPIO_EVENT_REPORT_DETAIL && priv->numevents < evcfg->gp_fifo_size) { - free(priv->events, M_GPIOC); - priv->numevents = evcfg->gp_fifo_size; - priv->events = malloc(priv->numevents * + void *tmp; + + tmp = realloc(priv->events, evcfg->gp_fifo_size * sizeof(struct gpio_event_detail), M_GPIOC, - M_WAITOK | M_ZERO); + M_NOWAIT | M_ZERO); + if (tmp == NULL) { + res = ENOMEM; + mtx_unlock(&priv->mtx); + break; + } + priv->events = tmp; + priv->numevents = evcfg->gp_fifo_size; priv->evidx_head = priv->evidx_tail = 0; } + priv->report_option = evcfg->gp_report_type; + mtx_unlock(&priv->mtx); break; case FIONBIO: /*