1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/gpio.h>
37#include <sys/ioccom.h>
38#include <sys/filio.h>
39#include <sys/fcntl.h>
40#include <sys/sigio.h>
41#include <sys/signalvar.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/uio.h>
45#include <sys/poll.h>
46#include <sys/selinfo.h>
47#include <sys/module.h>
48
49#include <dev/gpio/gpiobusvar.h>
50
51#include "gpio_if.h"
52#include "gpiobus_if.h"
53
54#undef GPIOC_DEBUG
55#ifdef GPIOC_DEBUG
56#define dprintf printf
57#define ddevice_printf device_printf
58#else
59#define dprintf(x, arg...)
60#define ddevice_printf(dev, x, arg...)
61#endif
62
63struct gpioc_softc {
64	device_t		sc_dev;		/* gpiocX dev */
65	device_t		sc_pdev;	/* gpioX dev */
66	struct cdev		*sc_ctl_dev;	/* controller device */
67	int			sc_unit;
68	int			sc_npins;
69	struct gpioc_pin_intr	*sc_pin_intr;
70};
71
72struct gpioc_pin_intr {
73	struct gpioc_softc				*sc;
74	gpio_pin_t					pin;
75	bool						config_locked;
76	int						intr_rid;
77	struct resource					*intr_res;
78	void						*intr_cookie;
79	struct mtx					mtx;
80	SLIST_HEAD(gpioc_privs_list, gpioc_privs)	privs;
81};
82
83
84struct gpioc_cdevpriv {
85	struct gpioc_softc			*sc;
86	struct selinfo				selinfo;
87	bool					async;
88	uint8_t					report_option;
89	struct sigio				*sigio;
90	struct mtx				mtx;
91	struct gpioc_pin_event			*events;
92	int					numevents;
93	int					evidx_head;
94	int					evidx_tail;
95	SLIST_HEAD(gpioc_pins_list, gpioc_pins)	pins;
96};
97
98struct gpioc_privs {
99	struct gpioc_cdevpriv		*priv;
100	SLIST_ENTRY(gpioc_privs)	next;
101};
102
103struct gpioc_pins {
104	struct gpioc_pin_intr	*pin;
105	int			eventcount;
106	int			firstevent;
107	SLIST_ENTRY(gpioc_pins)	next;
108};
109
110struct gpioc_pin_event {
111	struct gpioc_pins	*privpin;
112	sbintime_t		event_time;
113	bool			event_pin_state;
114};
115
116static MALLOC_DEFINE(M_GPIOC, "gpioc", "gpioc device data");
117
118static int	gpioc_allocate_pin_intr(struct gpioc_pin_intr*, uint32_t);
119static int	gpioc_release_pin_intr(struct gpioc_pin_intr*);
120static int	gpioc_attach_priv_pin(struct gpioc_cdevpriv*,
121		    struct gpioc_pin_intr*);
122static int	gpioc_detach_priv_pin(struct gpioc_cdevpriv*,
123		    struct gpioc_pin_intr*);
124static bool	gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv*,
125		    struct gpioc_pin_intr *intr_conf);
126static uint32_t	gpioc_get_intr_config(struct gpioc_softc*,
127		    struct gpioc_cdevpriv*, uint32_t pin);
128static int	gpioc_set_intr_config(struct gpioc_softc*,
129		    struct gpioc_cdevpriv*, uint32_t, uint32_t);
130static void	gpioc_interrupt_handler(void*);
131
132static int	gpioc_kqread(struct knote*, long);
133static void	gpioc_kqdetach(struct knote*);
134
135static int	gpioc_probe(device_t dev);
136static int	gpioc_attach(device_t dev);
137static int	gpioc_detach(device_t dev);
138
139static void	gpioc_cdevpriv_dtor(void*);
140
141static d_open_t		gpioc_open;
142static d_read_t		gpioc_read;
143static d_ioctl_t	gpioc_ioctl;
144static d_poll_t		gpioc_poll;
145static d_kqfilter_t	gpioc_kqfilter;
146
147static struct cdevsw gpioc_cdevsw = {
148	.d_version	= D_VERSION,
149	.d_open		= gpioc_open,
150	.d_read		= gpioc_read,
151	.d_ioctl	= gpioc_ioctl,
152	.d_poll		= gpioc_poll,
153	.d_kqfilter	= gpioc_kqfilter,
154	.d_name		= "gpioc",
155};
156
157static struct filterops gpioc_read_filterops = {
158	.f_isfd =	true,
159	.f_attach =	NULL,
160	.f_detach =	gpioc_kqdetach,
161	.f_event =	gpioc_kqread,
162	.f_touch =	NULL
163};
164
165static struct gpioc_pin_event *
166next_head_event(struct gpioc_cdevpriv *priv)
167{
168	struct gpioc_pin_event *rv;
169
170	rv = &priv->events[priv->evidx_head++];
171	if (priv->evidx_head == priv->numevents)
172		priv->evidx_head = 0;
173	return (rv);
174}
175
176static struct gpioc_pin_event *
177next_tail_event(struct gpioc_cdevpriv *priv)
178{
179	struct gpioc_pin_event *rv;
180
181	rv = &priv->events[priv->evidx_tail++];
182	if (priv->evidx_tail == priv->numevents)
183		priv->evidx_tail = 0;
184	return (rv);
185}
186
187static size_t
188number_of_events(struct gpioc_cdevpriv *priv)
189{
190	if (priv->evidx_head >= priv->evidx_tail)
191		return (priv->evidx_head - priv->evidx_tail);
192	else
193		return (priv->numevents + priv->evidx_head - priv->evidx_tail);
194}
195
196static int
197gpioc_allocate_pin_intr(struct gpioc_pin_intr *intr_conf, uint32_t flags)
198{
199	int err;
200
201	intr_conf->config_locked = true;
202	mtx_unlock(&intr_conf->mtx);
203
204	intr_conf->intr_res = gpio_alloc_intr_resource(intr_conf->pin->dev,
205	    &intr_conf->intr_rid, RF_ACTIVE, intr_conf->pin, flags);
206	if (intr_conf->intr_res == NULL) {
207		err = ENXIO;
208		goto error_exit;
209	}
210
211	err = bus_setup_intr(intr_conf->pin->dev, intr_conf->intr_res,
212	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, gpioc_interrupt_handler,
213	    intr_conf, &intr_conf->intr_cookie);
214	if (err != 0)
215		goto error_exit;
216
217	intr_conf->pin->flags = flags;
218
219error_exit:
220	mtx_lock(&intr_conf->mtx);
221	intr_conf->config_locked = false;
222	wakeup(&intr_conf->config_locked);
223
224	return (err);
225}
226
227static int
228gpioc_release_pin_intr(struct gpioc_pin_intr *intr_conf)
229{
230	int err;
231
232	intr_conf->config_locked = true;
233	mtx_unlock(&intr_conf->mtx);
234
235	if (intr_conf->intr_cookie != NULL) {
236		err = bus_teardown_intr(intr_conf->pin->dev,
237		    intr_conf->intr_res, intr_conf->intr_cookie);
238		if (err != 0)
239			goto error_exit;
240		else
241			intr_conf->intr_cookie = NULL;
242	}
243
244	if (intr_conf->intr_res != NULL) {
245		err = bus_release_resource(intr_conf->pin->dev, SYS_RES_IRQ,
246		    intr_conf->intr_rid, intr_conf->intr_res);
247		if (err != 0)
248			goto error_exit;
249		else {
250			intr_conf->intr_rid = 0;
251			intr_conf->intr_res = NULL;
252		}
253	}
254
255	intr_conf->pin->flags = 0;
256	err = 0;
257
258error_exit:
259	mtx_lock(&intr_conf->mtx);
260	intr_conf->config_locked = false;
261	wakeup(&intr_conf->config_locked);
262
263	return (err);
264}
265
266static int
267gpioc_attach_priv_pin(struct gpioc_cdevpriv *priv,
268    struct gpioc_pin_intr *intr_conf)
269{
270	struct gpioc_privs	*priv_link;
271	struct gpioc_pins	*pin_link;
272	unsigned int		consistency_a, consistency_b;
273
274	consistency_a = 0;
275	consistency_b = 0;
276	mtx_assert(&intr_conf->mtx, MA_OWNED);
277	mtx_lock(&priv->mtx);
278	SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
279		if (priv_link->priv == priv)
280			consistency_a++;
281	}
282	KASSERT(consistency_a <= 1,
283	    ("inconsistent links between pin config and cdevpriv"));
284	SLIST_FOREACH(pin_link, &priv->pins, next) {
285		if (pin_link->pin == intr_conf)
286			consistency_b++;
287	}
288	KASSERT(consistency_a == consistency_b,
289	    ("inconsistent links between pin config and cdevpriv"));
290	if (consistency_a == 1 && consistency_b == 1) {
291		mtx_unlock(&priv->mtx);
292		return (EEXIST);
293	}
294	priv_link = malloc(sizeof(struct gpioc_privs), M_GPIOC,
295	    M_NOWAIT | M_ZERO);
296	if (priv_link == NULL)
297	{
298		mtx_unlock(&priv->mtx);
299		return (ENOMEM);
300	}
301	pin_link = malloc(sizeof(struct gpioc_pins), M_GPIOC,
302	    M_NOWAIT | M_ZERO);
303	if (pin_link == NULL) {
304		mtx_unlock(&priv->mtx);
305		return (ENOMEM);
306	}
307	priv_link->priv = priv;
308	pin_link->pin = intr_conf;
309	SLIST_INSERT_HEAD(&intr_conf->privs, priv_link, next);
310	SLIST_INSERT_HEAD(&priv->pins, pin_link, next);
311	mtx_unlock(&priv->mtx);
312
313	return (0);
314}
315
316static int
317gpioc_detach_priv_pin(struct gpioc_cdevpriv *priv,
318    struct gpioc_pin_intr *intr_conf)
319{
320	struct gpioc_privs	*priv_link, *priv_link_temp;
321	struct gpioc_pins	*pin_link, *pin_link_temp;
322	unsigned int		consistency_a, consistency_b;
323
324	consistency_a = 0;
325	consistency_b = 0;
326	mtx_assert(&intr_conf->mtx, MA_OWNED);
327	mtx_lock(&priv->mtx);
328	SLIST_FOREACH_SAFE(priv_link, &intr_conf->privs, next, priv_link_temp) {
329		if (priv_link->priv == priv) {
330			SLIST_REMOVE(&intr_conf->privs, priv_link, gpioc_privs,
331			    next);
332			free(priv_link, M_GPIOC);
333			consistency_a++;
334		}
335	}
336	KASSERT(consistency_a <= 1,
337	    ("inconsistent links between pin config and cdevpriv"));
338	SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
339		if (pin_link->pin == intr_conf) {
340			/*
341			 * If the pin we're removing has events in the priv's
342			 * event fifo, we can't leave dangling pointers from
343			 * those events to the gpioc_pins struct we're about to
344			 * free.  We also can't remove random items and leave
345			 * holes in the events fifo, so just empty it out.
346			 */
347			if (pin_link->eventcount > 0) {
348				priv->evidx_head = priv->evidx_tail = 0;
349			}
350			SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
351			free(pin_link, M_GPIOC);
352			consistency_b++;
353		}
354	}
355	KASSERT(consistency_a == consistency_b,
356	    ("inconsistent links between pin config and cdevpriv"));
357	mtx_unlock(&priv->mtx);
358
359	return (0);
360}
361
362static bool
363gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv *priv,
364    struct gpioc_pin_intr *intr_conf)
365{
366	struct gpioc_privs	*priv_link;
367
368	mtx_assert(&intr_conf->mtx, MA_OWNED);
369
370	if (SLIST_EMPTY(&intr_conf->privs))
371		return (true);
372
373	SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
374		if (priv_link->priv != priv)
375			return (false);
376	}
377
378	return (true);
379}
380
381
382static uint32_t
383gpioc_get_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
384    uint32_t pin)
385{
386	struct gpioc_pin_intr	*intr_conf = &sc->sc_pin_intr[pin];
387	struct gpioc_privs	*priv_link;
388	uint32_t		flags;
389
390	flags = intr_conf->pin->flags;
391
392	if (flags == 0)
393		return (0);
394
395	mtx_lock(&intr_conf->mtx);
396	SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
397		if (priv_link->priv == priv) {
398			flags |= GPIO_INTR_ATTACHED;
399			break;
400		}
401	}
402	mtx_unlock(&intr_conf->mtx);
403
404	return (flags);
405}
406
407static int
408gpioc_set_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
409    uint32_t pin, uint32_t flags)
410{
411	struct gpioc_pin_intr *intr_conf = &sc->sc_pin_intr[pin];
412	int res;
413
414	res = 0;
415	if (intr_conf->pin->flags == 0 && flags == 0) {
416		/* No interrupt configured and none requested: Do nothing. */
417		return (0);
418	}
419	mtx_lock(&intr_conf->mtx);
420	while (intr_conf->config_locked == true)
421		mtx_sleep(&intr_conf->config_locked, &intr_conf->mtx, 0,
422		    "gpicfg", 0);
423	if (intr_conf->pin->flags == 0 && flags != 0) {
424		/*
425		 * No interrupt is configured, but one is requested: Allocate
426		 * and setup interrupt on the according pin.
427		 */
428		res = gpioc_allocate_pin_intr(intr_conf, flags);
429		if (res == 0)
430			res = gpioc_attach_priv_pin(priv, intr_conf);
431		if (res == EEXIST)
432			res = 0;
433	} else if (intr_conf->pin->flags == flags) {
434		/*
435		 * Same interrupt requested as already configured: Attach the
436		 * cdevpriv to the corresponding pin.
437		 */
438		res = gpioc_attach_priv_pin(priv, intr_conf);
439		if (res == EEXIST)
440			res = 0;
441	} else if (intr_conf->pin->flags != 0 && flags == 0) {
442		/*
443		 * Interrupt configured, but none requested: Teardown and
444		 * release the pin when no other cdevpriv is attached. Otherwise
445		 * just detach pin and cdevpriv from each other.
446		 */
447		if (gpioc_intr_reconfig_allowed(priv, intr_conf)) {
448			res = gpioc_release_pin_intr(intr_conf);
449		}
450		if (res == 0)
451			res = gpioc_detach_priv_pin(priv, intr_conf);
452	} else {
453		/*
454		 * Other flag requested than configured: Reconfigure when no
455		 * other cdevpriv is are attached to the pin.
456		 */
457		if (!gpioc_intr_reconfig_allowed(priv, intr_conf))
458			res = EBUSY;
459		else {
460			res = gpioc_release_pin_intr(intr_conf);
461			if (res == 0)
462				res = gpioc_allocate_pin_intr(intr_conf, flags);
463			if (res == 0)
464				res = gpioc_attach_priv_pin(priv, intr_conf);
465			if (res == EEXIST)
466				res = 0;
467		}
468	}
469	mtx_unlock(&intr_conf->mtx);
470
471	return (res);
472}
473
474static void
475gpioc_interrupt_handler(void *arg)
476{
477	struct gpioc_pin_intr *intr_conf;
478	struct gpioc_privs *privs;
479	struct gpioc_softc *sc;
480	sbintime_t evtime;
481	uint32_t pin_state;
482
483	intr_conf = arg;
484	sc = intr_conf->sc;
485
486	/* Capture time and pin state first. */
487	evtime = sbinuptime();
488	if (intr_conf->pin->flags & GPIO_INTR_EDGE_BOTH)
489		GPIO_PIN_GET(sc->sc_pdev, intr_conf->pin->pin, &pin_state);
490	else if (intr_conf->pin->flags & GPIO_INTR_EDGE_RISING)
491		pin_state = true;
492	else
493		pin_state = false;
494
495	mtx_lock(&intr_conf->mtx);
496
497	if (intr_conf->config_locked == true) {
498		ddevice_printf(sc->sc_dev, "Interrupt configuration in "
499		    "progress. Discarding interrupt on pin %d.\n",
500		    intr_conf->pin->pin);
501		mtx_unlock(&intr_conf->mtx);
502		return;
503	}
504
505	if (SLIST_EMPTY(&intr_conf->privs)) {
506		ddevice_printf(sc->sc_dev, "No file descriptor associated with "
507		    "occurred interrupt on pin %d.\n", intr_conf->pin->pin);
508		mtx_unlock(&intr_conf->mtx);
509		return;
510	}
511
512	SLIST_FOREACH(privs, &intr_conf->privs, next) {
513		struct gpioc_cdevpriv *priv = privs->priv;
514		struct gpioc_pins *privpin;
515		struct gpioc_pin_event *event;
516		mtx_lock(&priv->mtx);
517		SLIST_FOREACH(privpin, &priv->pins, next) {
518			if (privpin->pin == intr_conf)
519				break;
520		}
521		if (privpin == NULL) {
522			/* Should be impossible. */
523			ddevice_printf(sc->sc_dev, "Cannot find privpin\n");
524			mtx_unlock(&priv->mtx);
525			continue;
526		}
527
528		if (priv->report_option == GPIO_EVENT_REPORT_DETAIL) {
529			event = next_head_event(priv);
530			/* If head is overtaking tail, advance tail. */
531			if (priv->evidx_head == priv->evidx_tail)
532				next_tail_event(priv);
533		} else {
534			if (privpin->eventcount > 0)
535				event = &priv->events[privpin->firstevent + 1];
536			else {
537				privpin->firstevent = priv->evidx_head;
538				event = next_head_event(priv);
539				event->privpin = privpin;
540				event->event_time = evtime;
541				event->event_pin_state = pin_state;
542				event = next_head_event(priv);
543			}
544			++privpin->eventcount;
545		}
546		event->privpin = privpin;
547		event->event_time = evtime;
548		event->event_pin_state = pin_state;
549		wakeup(priv);
550		selwakeup(&priv->selinfo);
551		KNOTE_LOCKED(&priv->selinfo.si_note, 0);
552		if (priv->async == true && priv->sigio != NULL)
553			pgsigio(&priv->sigio, SIGIO, 0);
554		mtx_unlock(&priv->mtx);
555	}
556
557	mtx_unlock(&intr_conf->mtx);
558}
559
560static int
561gpioc_probe(device_t dev)
562{
563	device_set_desc(dev, "GPIO controller");
564	return (0);
565}
566
567static int
568gpioc_attach(device_t dev)
569{
570	int err;
571	struct gpioc_softc *sc;
572	struct make_dev_args devargs;
573
574	sc = device_get_softc(dev);
575	sc->sc_dev = dev;
576	sc->sc_pdev = device_get_parent(dev);
577	sc->sc_unit = device_get_unit(dev);
578
579	err = GPIO_PIN_MAX(sc->sc_pdev, &sc->sc_npins);
580	sc->sc_npins++; /* Number of pins is one more than max pin number. */
581	if (err != 0)
582		return (err);
583	sc->sc_pin_intr = malloc(sizeof(struct gpioc_pin_intr) * sc->sc_npins,
584	    M_GPIOC, M_WAITOK | M_ZERO);
585	for (int i = 0; i <= sc->sc_npins; i++) {
586		sc->sc_pin_intr[i].pin = malloc(sizeof(struct gpiobus_pin),
587		    M_GPIOC, M_WAITOK | M_ZERO);
588		sc->sc_pin_intr[i].sc = sc;
589		sc->sc_pin_intr[i].pin->pin = i;
590		sc->sc_pin_intr[i].pin->dev = sc->sc_pdev;
591		mtx_init(&sc->sc_pin_intr[i].mtx, "gpioc pin", NULL, MTX_DEF);
592		SLIST_INIT(&sc->sc_pin_intr[i].privs);
593	}
594
595	make_dev_args_init(&devargs);
596	devargs.mda_devsw = &gpioc_cdevsw;
597	devargs.mda_uid = UID_ROOT;
598	devargs.mda_gid = GID_WHEEL;
599	devargs.mda_mode = 0600;
600	devargs.mda_si_drv1 = sc;
601	err = make_dev_s(&devargs, &sc->sc_ctl_dev, "gpioc%d", sc->sc_unit);
602	if (err != 0) {
603		device_printf(dev, "Failed to create gpioc%d", sc->sc_unit);
604		return (ENXIO);
605	}
606
607	return (0);
608}
609
610static int
611gpioc_detach(device_t dev)
612{
613	struct gpioc_softc *sc = device_get_softc(dev);
614	int err;
615
616	if (sc->sc_ctl_dev)
617		destroy_dev(sc->sc_ctl_dev);
618
619	for (int i = 0; i <= sc->sc_npins; i++) {
620		mtx_destroy(&sc->sc_pin_intr[i].mtx);
621		free(sc->sc_pin_intr[i].pin, M_GPIOC);
622	}
623	free(sc->sc_pin_intr, M_GPIOC);
624
625	if ((err = bus_generic_detach(dev)) != 0)
626		return (err);
627
628	return (0);
629}
630
631static void
632gpioc_cdevpriv_dtor(void *data)
633{
634	struct gpioc_cdevpriv	*priv;
635	struct gpioc_privs	*priv_link, *priv_link_temp;
636	struct gpioc_pins	*pin_link, *pin_link_temp;
637	unsigned int		consistency;
638
639	priv = data;
640
641	SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
642		consistency = 0;
643		mtx_lock(&pin_link->pin->mtx);
644		while (pin_link->pin->config_locked == true)
645			mtx_sleep(&pin_link->pin->config_locked,
646			    &pin_link->pin->mtx, 0, "gpicfg", 0);
647		SLIST_FOREACH_SAFE(priv_link, &pin_link->pin->privs, next,
648		    priv_link_temp) {
649			if (priv_link->priv == priv) {
650				SLIST_REMOVE(&pin_link->pin->privs, priv_link,
651				    gpioc_privs, next);
652				free(priv_link, M_GPIOC);
653				consistency++;
654			}
655		}
656		KASSERT(consistency == 1,
657		    ("inconsistent links between pin config and cdevpriv"));
658		if (gpioc_intr_reconfig_allowed(priv, pin_link->pin)) {
659			gpioc_release_pin_intr(pin_link->pin);
660		}
661		mtx_unlock(&pin_link->pin->mtx);
662		SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
663		free(pin_link, M_GPIOC);
664	}
665
666	wakeup(&priv);
667	knlist_clear(&priv->selinfo.si_note, 0);
668	seldrain(&priv->selinfo);
669	knlist_destroy(&priv->selinfo.si_note);
670	funsetown(&priv->sigio);
671
672	mtx_destroy(&priv->mtx);
673	free(priv->events, M_GPIOC);
674	free(data, M_GPIOC);
675}
676
677static int
678gpioc_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
679{
680	struct gpioc_cdevpriv *priv;
681	int err;
682
683	priv = malloc(sizeof(*priv), M_GPIOC, M_WAITOK | M_ZERO);
684	priv->sc = dev->si_drv1;
685	priv->report_option = GPIO_EVENT_REPORT_DETAIL;
686	err = devfs_set_cdevpriv(priv, gpioc_cdevpriv_dtor);
687	if (err != 0) {
688		gpioc_cdevpriv_dtor(priv);
689		return (err);
690	}
691	mtx_init(&priv->mtx, "gpioc priv", NULL, MTX_DEF);
692	knlist_init_mtx(&priv->selinfo.si_note, &priv->mtx);
693
694	/*
695	 * Allocate a circular buffer for events.  The scheme we use for summary
696	 * reporting assumes there will always be a pair of events available to
697	 * record the first/last events on any pin, so we allocate 2 * npins.
698	 * Even though we actually default to detailed event reporting, 2 *
699	 * npins isn't a horrible fifo size for that either.
700	 */
701	priv->numevents = priv->sc->sc_npins * 2;
702	priv->events = malloc(priv->numevents * sizeof(struct gpio_event_detail),
703	    M_GPIOC, M_WAITOK | M_ZERO);
704
705	return (0);
706}
707
708static int
709gpioc_read(struct cdev *dev, struct uio *uio, int ioflag)
710{
711	struct gpioc_cdevpriv *priv;
712	struct gpioc_pin_event *event;
713	union {
714		struct gpio_event_summary sum;
715		struct gpio_event_detail  evt;
716		uint8_t 		  data[1];
717	} recbuf;
718	size_t recsize;
719	int err;
720
721	if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
722		return (err);
723
724	if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
725		recsize = sizeof(struct gpio_event_summary);
726	else
727		recsize = sizeof(struct gpio_event_detail);
728
729	if (uio->uio_resid < recsize)
730		return (EINVAL);
731
732	mtx_lock(&priv->mtx);
733	while (priv->evidx_head == priv->evidx_tail) {
734		if (SLIST_EMPTY(&priv->pins)) {
735			err = ENXIO;
736			break;
737		} else if (ioflag & O_NONBLOCK) {
738			err = EWOULDBLOCK;
739			break;
740		} else {
741			err = mtx_sleep(priv, &priv->mtx, PCATCH, "gpintr", 0);
742			if (err != 0)
743				break;
744		}
745	}
746
747	while (err == 0 && uio->uio_resid >= recsize &&
748           priv->evidx_tail != priv->evidx_head) {
749		event = next_tail_event(priv);
750		if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY) {
751			recbuf.sum.gp_first_time = event->event_time;
752			recbuf.sum.gp_pin = event->privpin->pin->pin->pin;
753			recbuf.sum.gp_count = event->privpin->eventcount;
754			recbuf.sum.gp_first_state = event->event_pin_state;
755			event = next_tail_event(priv);
756			recbuf.sum.gp_last_time = event->event_time;
757			recbuf.sum.gp_last_state = event->event_pin_state;
758			event->privpin->eventcount = 0;
759			event->privpin->firstevent = 0;
760		} else {
761			recbuf.evt.gp_time = event->event_time;
762			recbuf.evt.gp_pin = event->privpin->pin->pin->pin;
763			recbuf.evt.gp_pinstate = event->event_pin_state;
764		}
765		mtx_unlock(&priv->mtx);
766		err = uiomove(recbuf.data, recsize, uio);
767		mtx_lock(&priv->mtx);
768	}
769	mtx_unlock(&priv->mtx);
770	return (err);
771}
772
773static int
774gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
775    struct thread *td)
776{
777	device_t bus;
778	int max_pin, res;
779	struct gpioc_softc *sc = cdev->si_drv1;
780	struct gpioc_cdevpriv *priv;
781	struct gpio_pin pin;
782	struct gpio_req req;
783	struct gpio_access_32 *a32;
784	struct gpio_config_32 *c32;
785	struct gpio_event_config *evcfg;
786	uint32_t caps, intrflags;
787
788	bus = GPIO_GET_BUS(sc->sc_pdev);
789	if (bus == NULL)
790		return (EINVAL);
791	switch (cmd) {
792	case GPIOMAXPIN:
793		max_pin = -1;
794		res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
795		bcopy(&max_pin, arg, sizeof(max_pin));
796		break;
797	case GPIOGETCONFIG:
798		bcopy(arg, &pin, sizeof(pin));
799		dprintf("get config pin %d\n", pin.gp_pin);
800		res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
801		    &pin.gp_flags);
802		/* Fail early */
803		if (res)
804			break;
805		res = devfs_get_cdevpriv((void **)&priv);
806		if (res)
807			break;
808		pin.gp_flags |= gpioc_get_intr_config(sc, priv,
809		    pin.gp_pin);
810		GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
811		GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name);
812		bcopy(&pin, arg, sizeof(pin));
813		break;
814	case GPIOSETCONFIG:
815		bcopy(arg, &pin, sizeof(pin));
816		dprintf("set config pin %d\n", pin.gp_pin);
817		res = devfs_get_cdevpriv((void **)&priv);
818		if (res != 0)
819			break;
820		res = GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &caps);
821		if (res != 0)
822			break;
823		res = gpio_check_flags(caps, pin.gp_flags);
824		if (res != 0)
825			break;
826		intrflags = pin.gp_flags & GPIO_INTR_MASK;
827		/*
828		 * We can do only edge interrupts, and only if the
829		 * hardware supports that interrupt type on that pin.
830		 */
831		switch (intrflags) {
832		case GPIO_INTR_NONE:
833			break;
834		case GPIO_INTR_EDGE_RISING:
835		case GPIO_INTR_EDGE_FALLING:
836		case GPIO_INTR_EDGE_BOTH:
837			if ((intrflags & caps) == 0)
838				res = EOPNOTSUPP;
839			break;
840		default:
841			res = EINVAL;
842			break;
843		}
844		if (res != 0)
845			break;
846		res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
847		    (pin.gp_flags & ~GPIO_INTR_MASK));
848		if (res != 0)
849			break;
850		res = gpioc_set_intr_config(sc, priv, pin.gp_pin,
851		    intrflags);
852		break;
853	case GPIOGET:
854		bcopy(arg, &req, sizeof(req));
855		res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
856		    &req.gp_value);
857		dprintf("read pin %d -> %d\n",
858		    req.gp_pin, req.gp_value);
859		bcopy(&req, arg, sizeof(req));
860		break;
861	case GPIOSET:
862		bcopy(arg, &req, sizeof(req));
863		res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin,
864		    req.gp_value);
865		dprintf("write pin %d -> %d\n",
866		    req.gp_pin, req.gp_value);
867		break;
868	case GPIOTOGGLE:
869		bcopy(arg, &req, sizeof(req));
870		dprintf("toggle pin %d\n",
871		    req.gp_pin);
872		res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
873		break;
874	case GPIOSETNAME:
875		bcopy(arg, &pin, sizeof(pin));
876		dprintf("set name on pin %d\n", pin.gp_pin);
877		res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin,
878		    pin.gp_name);
879		break;
880	case GPIOACCESS32:
881		a32 = (struct gpio_access_32 *)arg;
882		res = GPIO_PIN_ACCESS_32(sc->sc_pdev, a32->first_pin,
883		    a32->clear_pins, a32->change_pins, &a32->orig_pins);
884		break;
885	case GPIOCONFIG32:
886		c32 = (struct gpio_config_32 *)arg;
887		res = GPIO_PIN_CONFIG_32(sc->sc_pdev, c32->first_pin,
888		    c32->num_pins, c32->pin_flags);
889		break;
890	case GPIOCONFIGEVENTS:
891		evcfg = (struct gpio_event_config *)arg;
892		res = devfs_get_cdevpriv((void **)&priv);
893		if (res != 0)
894			break;
895		/* If any pins have been configured, changes aren't allowed. */
896		if (!SLIST_EMPTY(&priv->pins)) {
897			res = EINVAL;
898			break;
899		}
900		if (evcfg->gp_report_type != GPIO_EVENT_REPORT_DETAIL &&
901		    evcfg->gp_report_type != GPIO_EVENT_REPORT_SUMMARY) {
902			res = EINVAL;
903			break;
904		}
905		priv->report_option = evcfg->gp_report_type;
906		/* Reallocate the events buffer if the user wants it bigger. */
907		if (priv->report_option == GPIO_EVENT_REPORT_DETAIL &&
908		    priv->numevents < evcfg->gp_fifo_size) {
909			free(priv->events, M_GPIOC);
910			priv->numevents = evcfg->gp_fifo_size;
911			priv->events = malloc(priv->numevents *
912			    sizeof(struct gpio_event_detail), M_GPIOC,
913			    M_WAITOK | M_ZERO);
914			priv->evidx_head = priv->evidx_tail = 0;
915		}
916		break;
917	case FIONBIO:
918		/*
919		 * This dummy handler is necessary to prevent fcntl()
920		 * from failing. The actual handling of non-blocking IO
921		 * is done using the O_NONBLOCK ioflag passed to the
922		 * read() syscall.
923		 */
924		res = 0;
925		break;
926	case FIOASYNC:
927		res = devfs_get_cdevpriv((void **)&priv);
928		if (res == 0) {
929			if (*(int *)arg == FASYNC)
930				priv->async = true;
931			else
932				priv->async = false;
933		}
934		break;
935	case FIOGETOWN:
936		res = devfs_get_cdevpriv((void **)&priv);
937		if (res == 0)
938			*(int *)arg = fgetown(&priv->sigio);
939		break;
940	case FIOSETOWN:
941		res = devfs_get_cdevpriv((void **)&priv);
942		if (res == 0)
943			res = fsetown(*(int *)arg, &priv->sigio);
944		break;
945	default:
946		return (ENOTTY);
947		break;
948	}
949
950	return (res);
951}
952
953static int
954gpioc_poll(struct cdev *dev, int events, struct thread *td)
955{
956	struct gpioc_cdevpriv *priv;
957	int err;
958	int revents;
959
960	revents = 0;
961
962	err = devfs_get_cdevpriv((void **)&priv);
963	if (err != 0) {
964		revents = POLLERR;
965		return (revents);
966	}
967
968	if (SLIST_EMPTY(&priv->pins)) {
969		revents = POLLHUP;
970		return (revents);
971	}
972
973	if (events & (POLLIN | POLLRDNORM)) {
974		if (priv->evidx_head != priv->evidx_tail)
975			revents |= events & (POLLIN | POLLRDNORM);
976		else
977			selrecord(td, &priv->selinfo);
978	}
979
980	return (revents);
981}
982
983static int
984gpioc_kqfilter(struct cdev *dev, struct knote *kn)
985{
986	struct gpioc_cdevpriv *priv;
987	struct knlist *knlist;
988	int err;
989
990	err = devfs_get_cdevpriv((void **)&priv);
991	if (err != 0)
992		return err;
993
994	if (SLIST_EMPTY(&priv->pins))
995		return (ENXIO);
996
997	switch(kn->kn_filter) {
998	case EVFILT_READ:
999		kn->kn_fop = &gpioc_read_filterops;
1000		kn->kn_hook = (void *)priv;
1001		break;
1002	default:
1003		return (EOPNOTSUPP);
1004	}
1005
1006	knlist = &priv->selinfo.si_note;
1007	knlist_add(knlist, kn, 0);
1008
1009	return (0);
1010}
1011
1012static int
1013gpioc_kqread(struct knote *kn, long hint)
1014{
1015	struct gpioc_cdevpriv *priv = kn->kn_hook;
1016	size_t recsize;
1017
1018
1019	if (SLIST_EMPTY(&priv->pins)) {
1020		kn->kn_flags |= EV_EOF;
1021		return (1);
1022	} else {
1023		if (priv->evidx_head != priv->evidx_tail) {
1024			if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
1025				recsize = sizeof(struct gpio_event_summary);
1026			else
1027				recsize = sizeof(struct gpio_event_detail);
1028			kn->kn_data = recsize * number_of_events(priv);
1029			return (1);
1030		}
1031	}
1032	return (0);
1033}
1034
1035static void
1036gpioc_kqdetach(struct knote *kn)
1037{
1038	struct gpioc_cdevpriv *priv = kn->kn_hook;
1039	struct knlist *knlist = &priv->selinfo.si_note;
1040
1041	knlist_remove(knlist, kn, 0);
1042}
1043
1044static device_method_t gpioc_methods[] = {
1045	/* Device interface */
1046	DEVMETHOD(device_probe,		gpioc_probe),
1047	DEVMETHOD(device_attach,	gpioc_attach),
1048	DEVMETHOD(device_detach,	gpioc_detach),
1049	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
1050	DEVMETHOD(device_suspend,	bus_generic_suspend),
1051	DEVMETHOD(device_resume,	bus_generic_resume),
1052
1053	DEVMETHOD_END
1054};
1055
1056driver_t gpioc_driver = {
1057	"gpioc",
1058	gpioc_methods,
1059	sizeof(struct gpioc_softc)
1060};
1061
1062devclass_t	gpioc_devclass;
1063
1064DRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0);
1065MODULE_VERSION(gpioc, 1);
1066