xref: /freebsd-src/sys/dev/proto/proto_core.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
167fb10f3SMarcel Moolenaar /*-
2*9f011bcaSMarcel Moolenaar  * Copyright (c) 2014, 2015, 2019 Marcel Moolenaar
367fb10f3SMarcel Moolenaar  * All rights reserved.
467fb10f3SMarcel Moolenaar  *
567fb10f3SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
667fb10f3SMarcel Moolenaar  * modification, are permitted provided that the following conditions
767fb10f3SMarcel Moolenaar  * are met:
867fb10f3SMarcel Moolenaar  *
967fb10f3SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
1067fb10f3SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
1167fb10f3SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
1267fb10f3SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
1367fb10f3SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
1467fb10f3SMarcel Moolenaar  *
1567fb10f3SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1667fb10f3SMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1767fb10f3SMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1867fb10f3SMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1967fb10f3SMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2067fb10f3SMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2167fb10f3SMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2267fb10f3SMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2367fb10f3SMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2467fb10f3SMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2567fb10f3SMarcel Moolenaar  */
2667fb10f3SMarcel Moolenaar 
2767fb10f3SMarcel Moolenaar #include <sys/param.h>
2867fb10f3SMarcel Moolenaar #include <sys/systm.h>
2967fb10f3SMarcel Moolenaar #include <sys/bus.h>
3067fb10f3SMarcel Moolenaar #include <sys/conf.h>
3167fb10f3SMarcel Moolenaar #include <sys/cons.h>
3267fb10f3SMarcel Moolenaar #include <sys/fcntl.h>
3367fb10f3SMarcel Moolenaar #include <sys/interrupt.h>
3467fb10f3SMarcel Moolenaar #include <sys/kdb.h>
3567fb10f3SMarcel Moolenaar #include <sys/kernel.h>
3667fb10f3SMarcel Moolenaar #include <sys/malloc.h>
3767fb10f3SMarcel Moolenaar #include <sys/mman.h>
3867fb10f3SMarcel Moolenaar #include <sys/proc.h>
3967fb10f3SMarcel Moolenaar #include <sys/queue.h>
4067fb10f3SMarcel Moolenaar #include <sys/reboot.h>
4167fb10f3SMarcel Moolenaar #include <machine/bus.h>
4267fb10f3SMarcel Moolenaar #include <sys/rman.h>
4367fb10f3SMarcel Moolenaar #include <sys/uio.h>
4467fb10f3SMarcel Moolenaar #include <machine/resource.h>
4567fb10f3SMarcel Moolenaar #include <machine/stdarg.h>
4667fb10f3SMarcel Moolenaar 
4767fb10f3SMarcel Moolenaar #include <dev/pci/pcivar.h>
4867fb10f3SMarcel Moolenaar 
4967fb10f3SMarcel Moolenaar #include <dev/proto/proto.h>
5067fb10f3SMarcel Moolenaar #include <dev/proto/proto_dev.h>
514f027abdSMarcel Moolenaar #include <dev/proto/proto_busdma.h>
5267fb10f3SMarcel Moolenaar 
5367fb10f3SMarcel Moolenaar CTASSERT(SYS_RES_IRQ != PROTO_RES_UNUSED &&
543a232946SMarcel Moolenaar     SYS_RES_DRQ != PROTO_RES_UNUSED &&
5567fb10f3SMarcel Moolenaar     SYS_RES_MEMORY != PROTO_RES_UNUSED &&
5667fb10f3SMarcel Moolenaar     SYS_RES_IOPORT != PROTO_RES_UNUSED);
5767fb10f3SMarcel Moolenaar CTASSERT(SYS_RES_IRQ != PROTO_RES_PCICFG &&
583a232946SMarcel Moolenaar     SYS_RES_DRQ != PROTO_RES_PCICFG &&
5967fb10f3SMarcel Moolenaar     SYS_RES_MEMORY != PROTO_RES_PCICFG &&
6067fb10f3SMarcel Moolenaar     SYS_RES_IOPORT != PROTO_RES_PCICFG);
614f027abdSMarcel Moolenaar CTASSERT(SYS_RES_IRQ != PROTO_RES_BUSDMA &&
623a232946SMarcel Moolenaar     SYS_RES_DRQ != PROTO_RES_BUSDMA &&
634f027abdSMarcel Moolenaar     SYS_RES_MEMORY != PROTO_RES_BUSDMA &&
644f027abdSMarcel Moolenaar     SYS_RES_IOPORT != PROTO_RES_BUSDMA);
6567fb10f3SMarcel Moolenaar 
6667fb10f3SMarcel Moolenaar char proto_driver_name[] = "proto";
6767fb10f3SMarcel Moolenaar 
6867fb10f3SMarcel Moolenaar static d_open_t proto_open;
6967fb10f3SMarcel Moolenaar static d_close_t proto_close;
7067fb10f3SMarcel Moolenaar static d_read_t proto_read;
7167fb10f3SMarcel Moolenaar static d_write_t proto_write;
7267fb10f3SMarcel Moolenaar static d_ioctl_t proto_ioctl;
7367fb10f3SMarcel Moolenaar static d_mmap_t proto_mmap;
7467fb10f3SMarcel Moolenaar 
7567fb10f3SMarcel Moolenaar struct cdevsw proto_devsw = {
7667fb10f3SMarcel Moolenaar 	.d_version = D_VERSION,
7767fb10f3SMarcel Moolenaar 	.d_flags = 0,
7867fb10f3SMarcel Moolenaar 	.d_name = proto_driver_name,
7967fb10f3SMarcel Moolenaar 	.d_open = proto_open,
8067fb10f3SMarcel Moolenaar 	.d_close = proto_close,
8167fb10f3SMarcel Moolenaar 	.d_read = proto_read,
8267fb10f3SMarcel Moolenaar 	.d_write = proto_write,
8367fb10f3SMarcel Moolenaar 	.d_ioctl = proto_ioctl,
8467fb10f3SMarcel Moolenaar 	.d_mmap = proto_mmap,
8567fb10f3SMarcel Moolenaar };
8667fb10f3SMarcel Moolenaar 
8767fb10f3SMarcel Moolenaar static MALLOC_DEFINE(M_PROTO, "PROTO", "PROTO driver");
8867fb10f3SMarcel Moolenaar 
8967fb10f3SMarcel Moolenaar int
proto_add_resource(struct proto_softc * sc,int type,int rid,struct resource * res)9067fb10f3SMarcel Moolenaar proto_add_resource(struct proto_softc *sc, int type, int rid,
9167fb10f3SMarcel Moolenaar     struct resource *res)
9267fb10f3SMarcel Moolenaar {
9367fb10f3SMarcel Moolenaar 	struct proto_res *r;
9467fb10f3SMarcel Moolenaar 
9567fb10f3SMarcel Moolenaar 	if (type == PROTO_RES_UNUSED)
9667fb10f3SMarcel Moolenaar 		return (EINVAL);
9767fb10f3SMarcel Moolenaar 	if (sc->sc_rescnt == PROTO_RES_MAX)
9867fb10f3SMarcel Moolenaar 		return (ENOSPC);
9967fb10f3SMarcel Moolenaar 
10067fb10f3SMarcel Moolenaar 	r = sc->sc_res + sc->sc_rescnt++;
10167fb10f3SMarcel Moolenaar 	r->r_type = type;
10267fb10f3SMarcel Moolenaar 	r->r_rid = rid;
1034f027abdSMarcel Moolenaar 	r->r_d.res = res;
10467fb10f3SMarcel Moolenaar 	return (0);
10567fb10f3SMarcel Moolenaar }
10667fb10f3SMarcel Moolenaar 
10767fb10f3SMarcel Moolenaar #ifdef notyet
10867fb10f3SMarcel Moolenaar static int
proto_intr(void * arg)10967fb10f3SMarcel Moolenaar proto_intr(void *arg)
11067fb10f3SMarcel Moolenaar {
11167fb10f3SMarcel Moolenaar 	struct proto_softc *sc = arg;
11267fb10f3SMarcel Moolenaar 
11367fb10f3SMarcel Moolenaar 	/* XXX TODO */
11467fb10f3SMarcel Moolenaar 	return (FILTER_HANDLED);
11567fb10f3SMarcel Moolenaar }
11667fb10f3SMarcel Moolenaar #endif
11767fb10f3SMarcel Moolenaar 
11867fb10f3SMarcel Moolenaar int
proto_probe(device_t dev,const char * prefix,char *** devnamesp)119be00e098SMarcel Moolenaar proto_probe(device_t dev, const char *prefix, char ***devnamesp)
120be00e098SMarcel Moolenaar {
121be00e098SMarcel Moolenaar 	char **devnames = *devnamesp;
122be00e098SMarcel Moolenaar 	const char *dn, *ep, *ev;
123be00e098SMarcel Moolenaar 	size_t pfxlen;
124be00e098SMarcel Moolenaar 	int idx, names;
125be00e098SMarcel Moolenaar 
126be00e098SMarcel Moolenaar 	if (devnames == NULL) {
127be00e098SMarcel Moolenaar 		pfxlen = strlen(prefix);
128be00e098SMarcel Moolenaar 		names = 1;	/* NULL pointer */
129be00e098SMarcel Moolenaar 		ev = kern_getenv("hw.proto.attach");
130be00e098SMarcel Moolenaar 		if (ev != NULL) {
131be00e098SMarcel Moolenaar 			dn = ev;
132be00e098SMarcel Moolenaar 			while (*dn != '\0') {
133be00e098SMarcel Moolenaar 				ep = dn;
134be00e098SMarcel Moolenaar 				while (*ep != ',' && *ep != '\0')
135be00e098SMarcel Moolenaar 					ep++;
136be00e098SMarcel Moolenaar 				if ((ep - dn) > pfxlen &&
137be00e098SMarcel Moolenaar 				    strncmp(dn, prefix, pfxlen) == 0)
138be00e098SMarcel Moolenaar 					names++;
139be00e098SMarcel Moolenaar 				dn = (*ep == ',') ? ep + 1 : ep;
140be00e098SMarcel Moolenaar 			}
141be00e098SMarcel Moolenaar 		}
142be00e098SMarcel Moolenaar 		devnames = malloc(names * sizeof(caddr_t), M_DEVBUF,
143be00e098SMarcel Moolenaar 		    M_WAITOK | M_ZERO);
144be00e098SMarcel Moolenaar 		*devnamesp = devnames;
145be00e098SMarcel Moolenaar 		if (ev != NULL) {
146be00e098SMarcel Moolenaar 			dn = ev;
147be00e098SMarcel Moolenaar 			idx = 0;
148be00e098SMarcel Moolenaar 			while (*dn != '\0') {
149be00e098SMarcel Moolenaar 				ep = dn;
150be00e098SMarcel Moolenaar 				while (*ep != ',' && *ep != '\0')
151be00e098SMarcel Moolenaar 					ep++;
152be00e098SMarcel Moolenaar 				if ((ep - dn) > pfxlen &&
153be00e098SMarcel Moolenaar 				    strncmp(dn, prefix, pfxlen) == 0) {
154be00e098SMarcel Moolenaar 					devnames[idx] = malloc(ep - dn + 1,
155be00e098SMarcel Moolenaar 					    M_DEVBUF, M_WAITOK | M_ZERO);
156be00e098SMarcel Moolenaar 					memcpy(devnames[idx], dn, ep - dn);
157be00e098SMarcel Moolenaar 					idx++;
158be00e098SMarcel Moolenaar 				}
159be00e098SMarcel Moolenaar 				dn = (*ep == ',') ? ep + 1 : ep;
160be00e098SMarcel Moolenaar 			}
161be00e098SMarcel Moolenaar 			freeenv(__DECONST(char *, ev));
162be00e098SMarcel Moolenaar 		}
163be00e098SMarcel Moolenaar 	}
164be00e098SMarcel Moolenaar 
165be00e098SMarcel Moolenaar 	dn = device_get_desc(dev);
166be00e098SMarcel Moolenaar 	while (*devnames != NULL) {
167be00e098SMarcel Moolenaar 		if (strcmp(dn, *devnames) == 0)
168be00e098SMarcel Moolenaar 			return (BUS_PROBE_SPECIFIC);
169be00e098SMarcel Moolenaar 		devnames++;
170be00e098SMarcel Moolenaar 	}
171be00e098SMarcel Moolenaar 	return (BUS_PROBE_HOOVER);
172be00e098SMarcel Moolenaar }
173be00e098SMarcel Moolenaar 
174be00e098SMarcel Moolenaar int
proto_attach(device_t dev)17567fb10f3SMarcel Moolenaar proto_attach(device_t dev)
17667fb10f3SMarcel Moolenaar {
17767fb10f3SMarcel Moolenaar 	struct proto_softc *sc;
17867fb10f3SMarcel Moolenaar 	struct proto_res *r;
17967fb10f3SMarcel Moolenaar 	u_int res;
18067fb10f3SMarcel Moolenaar 
18167fb10f3SMarcel Moolenaar 	sc = device_get_softc(dev);
18267fb10f3SMarcel Moolenaar 	sc->sc_dev = dev;
183*9f011bcaSMarcel Moolenaar 	mtx_init(&sc->sc_mtx, "proto-softc", NULL, MTX_DEF);
18467fb10f3SMarcel Moolenaar 
18567fb10f3SMarcel Moolenaar 	for (res = 0; res < sc->sc_rescnt; res++) {
18667fb10f3SMarcel Moolenaar 		r = sc->sc_res + res;
18767fb10f3SMarcel Moolenaar 		switch (r->r_type) {
18867fb10f3SMarcel Moolenaar 		case SYS_RES_IRQ:
18967fb10f3SMarcel Moolenaar 			/* XXX TODO */
19067fb10f3SMarcel Moolenaar 			break;
1913a232946SMarcel Moolenaar 		case SYS_RES_DRQ:
1923a232946SMarcel Moolenaar 			break;
19367fb10f3SMarcel Moolenaar 		case SYS_RES_MEMORY:
19467fb10f3SMarcel Moolenaar 		case SYS_RES_IOPORT:
1954f027abdSMarcel Moolenaar 			r->r_size = rman_get_size(r->r_d.res);
196dc9874eaSEd Maste 			r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0600,
19767fb10f3SMarcel Moolenaar 			    "proto/%s/%02x.%s", device_get_desc(dev), r->r_rid,
19867fb10f3SMarcel Moolenaar 			    (r->r_type == SYS_RES_IOPORT) ? "io" : "mem");
19967fb10f3SMarcel Moolenaar 			r->r_u.cdev->si_drv1 = sc;
20067fb10f3SMarcel Moolenaar 			r->r_u.cdev->si_drv2 = r;
20167fb10f3SMarcel Moolenaar 			break;
20267fb10f3SMarcel Moolenaar 		case PROTO_RES_PCICFG:
20367fb10f3SMarcel Moolenaar 			r->r_size = 4096;
204dc9874eaSEd Maste 			r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0600,
20567fb10f3SMarcel Moolenaar 			    "proto/%s/pcicfg", device_get_desc(dev));
20667fb10f3SMarcel Moolenaar 			r->r_u.cdev->si_drv1 = sc;
20767fb10f3SMarcel Moolenaar 			r->r_u.cdev->si_drv2 = r;
20867fb10f3SMarcel Moolenaar 			break;
2094f027abdSMarcel Moolenaar 		case PROTO_RES_BUSDMA:
2104f027abdSMarcel Moolenaar 			r->r_d.busdma = proto_busdma_attach(sc);
2114f027abdSMarcel Moolenaar 			r->r_size = 0;	/* no read(2) nor write(2) */
212dc9874eaSEd Maste 			r->r_u.cdev = make_dev(&proto_devsw, res, 0, 0, 0600,
2134f027abdSMarcel Moolenaar 			    "proto/%s/busdma", device_get_desc(dev));
2144f027abdSMarcel Moolenaar 			r->r_u.cdev->si_drv1 = sc;
2154f027abdSMarcel Moolenaar 			r->r_u.cdev->si_drv2 = r;
2164f027abdSMarcel Moolenaar 			break;
21767fb10f3SMarcel Moolenaar 		}
21867fb10f3SMarcel Moolenaar 	}
21967fb10f3SMarcel Moolenaar 	return (0);
22067fb10f3SMarcel Moolenaar }
22167fb10f3SMarcel Moolenaar 
22267fb10f3SMarcel Moolenaar int
proto_detach(device_t dev)22367fb10f3SMarcel Moolenaar proto_detach(device_t dev)
22467fb10f3SMarcel Moolenaar {
22567fb10f3SMarcel Moolenaar 	struct proto_softc *sc;
22667fb10f3SMarcel Moolenaar 	struct proto_res *r;
22767fb10f3SMarcel Moolenaar 	u_int res;
22867fb10f3SMarcel Moolenaar 
22967fb10f3SMarcel Moolenaar 	sc = device_get_softc(dev);
23067fb10f3SMarcel Moolenaar 
231*9f011bcaSMarcel Moolenaar 	mtx_lock(&sc->sc_mtx);
232*9f011bcaSMarcel Moolenaar 	if (sc->sc_opencnt == 0)
233*9f011bcaSMarcel Moolenaar 		sc->sc_opencnt = -1;
234*9f011bcaSMarcel Moolenaar 	mtx_unlock(&sc->sc_mtx);
235*9f011bcaSMarcel Moolenaar 	if (sc->sc_opencnt > 0)
23667fb10f3SMarcel Moolenaar 		return (EBUSY);
23767fb10f3SMarcel Moolenaar 
23867fb10f3SMarcel Moolenaar 	for (res = 0; res < sc->sc_rescnt; res++) {
23967fb10f3SMarcel Moolenaar 		r = sc->sc_res + res;
240*9f011bcaSMarcel Moolenaar 
24167fb10f3SMarcel Moolenaar 		switch (r->r_type) {
24267fb10f3SMarcel Moolenaar 		case SYS_RES_IRQ:
24367fb10f3SMarcel Moolenaar 			/* XXX TODO */
2444f027abdSMarcel Moolenaar 			bus_release_resource(dev, r->r_type, r->r_rid,
2454f027abdSMarcel Moolenaar 			    r->r_d.res);
24667fb10f3SMarcel Moolenaar 			break;
2473a232946SMarcel Moolenaar 		case SYS_RES_DRQ:
2483a232946SMarcel Moolenaar 			bus_release_resource(dev, r->r_type, r->r_rid,
2493a232946SMarcel Moolenaar 			    r->r_d.res);
2503a232946SMarcel Moolenaar 			break;
25167fb10f3SMarcel Moolenaar 		case SYS_RES_MEMORY:
25267fb10f3SMarcel Moolenaar 		case SYS_RES_IOPORT:
253*9f011bcaSMarcel Moolenaar 			destroy_dev(r->r_u.cdev);
2544f027abdSMarcel Moolenaar 			bus_release_resource(dev, r->r_type, r->r_rid,
2554f027abdSMarcel Moolenaar 			    r->r_d.res);
2564f027abdSMarcel Moolenaar 			break;
25767fb10f3SMarcel Moolenaar 		case PROTO_RES_PCICFG:
25867fb10f3SMarcel Moolenaar 			destroy_dev(r->r_u.cdev);
25967fb10f3SMarcel Moolenaar 			break;
2604f027abdSMarcel Moolenaar 		case PROTO_RES_BUSDMA:
2614f027abdSMarcel Moolenaar 			destroy_dev(r->r_u.cdev);
262*9f011bcaSMarcel Moolenaar 			proto_busdma_detach(sc, r->r_d.busdma);
2634f027abdSMarcel Moolenaar 			break;
26467fb10f3SMarcel Moolenaar 		}
26567fb10f3SMarcel Moolenaar 		r->r_type = PROTO_RES_UNUSED;
26667fb10f3SMarcel Moolenaar 	}
267*9f011bcaSMarcel Moolenaar 	mtx_lock(&sc->sc_mtx);
26867fb10f3SMarcel Moolenaar 	sc->sc_rescnt = 0;
269*9f011bcaSMarcel Moolenaar 	sc->sc_opencnt = 0;
270*9f011bcaSMarcel Moolenaar 	mtx_unlock(&sc->sc_mtx);
271*9f011bcaSMarcel Moolenaar 	mtx_destroy(&sc->sc_mtx);
27267fb10f3SMarcel Moolenaar 	return (0);
27367fb10f3SMarcel Moolenaar }
27467fb10f3SMarcel Moolenaar 
27567fb10f3SMarcel Moolenaar /*
27667fb10f3SMarcel Moolenaar  * Device functions
27767fb10f3SMarcel Moolenaar  */
27867fb10f3SMarcel Moolenaar 
27967fb10f3SMarcel Moolenaar static int
proto_open(struct cdev * cdev,int oflags,int devtype,struct thread * td)28067fb10f3SMarcel Moolenaar proto_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
28167fb10f3SMarcel Moolenaar {
28267fb10f3SMarcel Moolenaar 	struct proto_res *r;
283*9f011bcaSMarcel Moolenaar 	struct proto_softc *sc;
284*9f011bcaSMarcel Moolenaar 	int error;
28567fb10f3SMarcel Moolenaar 
286*9f011bcaSMarcel Moolenaar 	sc = cdev->si_drv1;
287*9f011bcaSMarcel Moolenaar 	mtx_lock(&sc->sc_mtx);
288*9f011bcaSMarcel Moolenaar 	if (sc->sc_opencnt >= 0) {
28967fb10f3SMarcel Moolenaar 		r = cdev->si_drv2;
290*9f011bcaSMarcel Moolenaar 		if (!r->r_opened) {
291*9f011bcaSMarcel Moolenaar 			r->r_opened = 1;
292*9f011bcaSMarcel Moolenaar 			sc->sc_opencnt++;
293*9f011bcaSMarcel Moolenaar 			error = 0;
294*9f011bcaSMarcel Moolenaar 		} else
295*9f011bcaSMarcel Moolenaar 			error = EBUSY;
296*9f011bcaSMarcel Moolenaar 	} else
297*9f011bcaSMarcel Moolenaar 		error = ENXIO;
298*9f011bcaSMarcel Moolenaar 	mtx_unlock(&sc->sc_mtx);
299*9f011bcaSMarcel Moolenaar 	return (error);
30067fb10f3SMarcel Moolenaar }
30167fb10f3SMarcel Moolenaar 
30267fb10f3SMarcel Moolenaar static int
proto_close(struct cdev * cdev,int fflag,int devtype,struct thread * td)30367fb10f3SMarcel Moolenaar proto_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
30467fb10f3SMarcel Moolenaar {
30567fb10f3SMarcel Moolenaar 	struct proto_res *r;
3064f027abdSMarcel Moolenaar 	struct proto_softc *sc;
307*9f011bcaSMarcel Moolenaar 	int error;
30867fb10f3SMarcel Moolenaar 
3094f027abdSMarcel Moolenaar 	sc = cdev->si_drv1;
310*9f011bcaSMarcel Moolenaar 	mtx_lock(&sc->sc_mtx);
311*9f011bcaSMarcel Moolenaar 	if (sc->sc_opencnt > 0) {
31267fb10f3SMarcel Moolenaar 		r = cdev->si_drv2;
313*9f011bcaSMarcel Moolenaar 		if (r->r_opened) {
3144f027abdSMarcel Moolenaar 			if (r->r_type == PROTO_RES_BUSDMA)
3154f027abdSMarcel Moolenaar 				proto_busdma_cleanup(sc, r->r_d.busdma);
316*9f011bcaSMarcel Moolenaar 			r->r_opened = 0;
317*9f011bcaSMarcel Moolenaar 			sc->sc_opencnt--;
318*9f011bcaSMarcel Moolenaar 			error = 0;
319*9f011bcaSMarcel Moolenaar 		} else
320*9f011bcaSMarcel Moolenaar 			error = ENXIO;
321*9f011bcaSMarcel Moolenaar 	} else
322*9f011bcaSMarcel Moolenaar 		error = ENXIO;
323*9f011bcaSMarcel Moolenaar 	mtx_unlock(&sc->sc_mtx);
324*9f011bcaSMarcel Moolenaar 	return (error);
32567fb10f3SMarcel Moolenaar }
32667fb10f3SMarcel Moolenaar 
32767fb10f3SMarcel Moolenaar static int
proto_read(struct cdev * cdev,struct uio * uio,int ioflag)32867fb10f3SMarcel Moolenaar proto_read(struct cdev *cdev, struct uio *uio, int ioflag)
32967fb10f3SMarcel Moolenaar {
33067fb10f3SMarcel Moolenaar 	union {
33167fb10f3SMarcel Moolenaar 		uint8_t	x1[8];
33267fb10f3SMarcel Moolenaar 		uint16_t x2[4];
33367fb10f3SMarcel Moolenaar 		uint32_t x4[2];
33467fb10f3SMarcel Moolenaar 		uint64_t x8[1];
33567fb10f3SMarcel Moolenaar 	} buf;
33667fb10f3SMarcel Moolenaar 	struct proto_softc *sc;
33767fb10f3SMarcel Moolenaar 	struct proto_res *r;
33867fb10f3SMarcel Moolenaar 	device_t dev;
33967fb10f3SMarcel Moolenaar 	off_t ofs;
34067fb10f3SMarcel Moolenaar 	u_long width;
34167fb10f3SMarcel Moolenaar 	int error;
34267fb10f3SMarcel Moolenaar 
34367fb10f3SMarcel Moolenaar 	sc = cdev->si_drv1;
34467fb10f3SMarcel Moolenaar 	dev = sc->sc_dev;
34567fb10f3SMarcel Moolenaar 	r = cdev->si_drv2;
34667fb10f3SMarcel Moolenaar 
34767fb10f3SMarcel Moolenaar 	width = uio->uio_resid;
34867fb10f3SMarcel Moolenaar 	if (width < 1 || width > 8 || bitcount16(width) > 1)
34967fb10f3SMarcel Moolenaar 		return (EIO);
35067fb10f3SMarcel Moolenaar 	ofs = uio->uio_offset;
35167fb10f3SMarcel Moolenaar 	if (ofs + width > r->r_size)
35267fb10f3SMarcel Moolenaar 		return (EIO);
35367fb10f3SMarcel Moolenaar 
35467fb10f3SMarcel Moolenaar 	switch (width) {
35567fb10f3SMarcel Moolenaar 	case 1:
35667fb10f3SMarcel Moolenaar 		buf.x1[0] = (r->r_type == PROTO_RES_PCICFG) ?
3574f027abdSMarcel Moolenaar 		    pci_read_config(dev, ofs, 1) : bus_read_1(r->r_d.res, ofs);
35867fb10f3SMarcel Moolenaar 		break;
35967fb10f3SMarcel Moolenaar 	case 2:
36067fb10f3SMarcel Moolenaar 		buf.x2[0] = (r->r_type == PROTO_RES_PCICFG) ?
3614f027abdSMarcel Moolenaar 		    pci_read_config(dev, ofs, 2) : bus_read_2(r->r_d.res, ofs);
36267fb10f3SMarcel Moolenaar 		break;
36367fb10f3SMarcel Moolenaar 	case 4:
36467fb10f3SMarcel Moolenaar 		buf.x4[0] = (r->r_type == PROTO_RES_PCICFG) ?
3654f027abdSMarcel Moolenaar 		    pci_read_config(dev, ofs, 4) : bus_read_4(r->r_d.res, ofs);
36667fb10f3SMarcel Moolenaar 		break;
36767fb10f3SMarcel Moolenaar #ifndef __i386__
36867fb10f3SMarcel Moolenaar 	case 8:
36967fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
37067fb10f3SMarcel Moolenaar 			return (EINVAL);
3714f027abdSMarcel Moolenaar 		buf.x8[0] = bus_read_8(r->r_d.res, ofs);
37267fb10f3SMarcel Moolenaar 		break;
37367fb10f3SMarcel Moolenaar #endif
37467fb10f3SMarcel Moolenaar 	default:
37567fb10f3SMarcel Moolenaar 		return (EIO);
37667fb10f3SMarcel Moolenaar 	}
37767fb10f3SMarcel Moolenaar 
37867fb10f3SMarcel Moolenaar 	error = uiomove(&buf, width, uio);
37967fb10f3SMarcel Moolenaar 	return (error);
38067fb10f3SMarcel Moolenaar }
38167fb10f3SMarcel Moolenaar 
38267fb10f3SMarcel Moolenaar static int
proto_write(struct cdev * cdev,struct uio * uio,int ioflag)38367fb10f3SMarcel Moolenaar proto_write(struct cdev *cdev, struct uio *uio, int ioflag)
38467fb10f3SMarcel Moolenaar {
38567fb10f3SMarcel Moolenaar 	union {
38667fb10f3SMarcel Moolenaar 		uint8_t	x1[8];
38767fb10f3SMarcel Moolenaar 		uint16_t x2[4];
38867fb10f3SMarcel Moolenaar 		uint32_t x4[2];
38967fb10f3SMarcel Moolenaar 		uint64_t x8[1];
39067fb10f3SMarcel Moolenaar 	} buf;
39167fb10f3SMarcel Moolenaar 	struct proto_softc *sc;
39267fb10f3SMarcel Moolenaar 	struct proto_res *r;
39367fb10f3SMarcel Moolenaar 	device_t dev;
39467fb10f3SMarcel Moolenaar 	off_t ofs;
39567fb10f3SMarcel Moolenaar 	u_long width;
39667fb10f3SMarcel Moolenaar 	int error;
39767fb10f3SMarcel Moolenaar 
39867fb10f3SMarcel Moolenaar 	sc = cdev->si_drv1;
39967fb10f3SMarcel Moolenaar 	dev = sc->sc_dev;
40067fb10f3SMarcel Moolenaar 	r = cdev->si_drv2;
40167fb10f3SMarcel Moolenaar 
40267fb10f3SMarcel Moolenaar 	width = uio->uio_resid;
40367fb10f3SMarcel Moolenaar 	if (width < 1 || width > 8 || bitcount16(width) > 1)
40467fb10f3SMarcel Moolenaar 		return (EIO);
40567fb10f3SMarcel Moolenaar 	ofs = uio->uio_offset;
40667fb10f3SMarcel Moolenaar 	if (ofs + width > r->r_size)
40767fb10f3SMarcel Moolenaar 		return (EIO);
40867fb10f3SMarcel Moolenaar 
40967fb10f3SMarcel Moolenaar 	error = uiomove(&buf, width, uio);
41067fb10f3SMarcel Moolenaar 	if (error)
41167fb10f3SMarcel Moolenaar 		return (error);
41267fb10f3SMarcel Moolenaar 
41367fb10f3SMarcel Moolenaar 	switch (width) {
41467fb10f3SMarcel Moolenaar 	case 1:
41567fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
41667fb10f3SMarcel Moolenaar 			pci_write_config(dev, ofs, buf.x1[0], 1);
41767fb10f3SMarcel Moolenaar 		else
4184f027abdSMarcel Moolenaar 			bus_write_1(r->r_d.res, ofs, buf.x1[0]);
41967fb10f3SMarcel Moolenaar 		break;
42067fb10f3SMarcel Moolenaar 	case 2:
42167fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
42267fb10f3SMarcel Moolenaar 			pci_write_config(dev, ofs, buf.x2[0], 2);
42367fb10f3SMarcel Moolenaar 		else
4244f027abdSMarcel Moolenaar 			bus_write_2(r->r_d.res, ofs, buf.x2[0]);
42567fb10f3SMarcel Moolenaar 		break;
42667fb10f3SMarcel Moolenaar 	case 4:
42767fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
42867fb10f3SMarcel Moolenaar 			pci_write_config(dev, ofs, buf.x4[0], 4);
42967fb10f3SMarcel Moolenaar 		else
4304f027abdSMarcel Moolenaar 			bus_write_4(r->r_d.res, ofs, buf.x4[0]);
43167fb10f3SMarcel Moolenaar 		break;
43267fb10f3SMarcel Moolenaar #ifndef __i386__
43367fb10f3SMarcel Moolenaar 	case 8:
43467fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
43567fb10f3SMarcel Moolenaar 			return (EINVAL);
4364f027abdSMarcel Moolenaar 		bus_write_8(r->r_d.res, ofs, buf.x8[0]);
43767fb10f3SMarcel Moolenaar 		break;
43867fb10f3SMarcel Moolenaar #endif
43967fb10f3SMarcel Moolenaar 	default:
44067fb10f3SMarcel Moolenaar 		return (EIO);
44167fb10f3SMarcel Moolenaar 	}
44267fb10f3SMarcel Moolenaar 
44367fb10f3SMarcel Moolenaar 	return (0);
44467fb10f3SMarcel Moolenaar }
44567fb10f3SMarcel Moolenaar 
44667fb10f3SMarcel Moolenaar static int
proto_ioctl(struct cdev * cdev,u_long cmd,caddr_t data,int fflag,struct thread * td)44767fb10f3SMarcel Moolenaar proto_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
44867fb10f3SMarcel Moolenaar     struct thread *td)
44967fb10f3SMarcel Moolenaar {
45067fb10f3SMarcel Moolenaar 	struct proto_ioc_region *region;
4514f027abdSMarcel Moolenaar 	struct proto_ioc_busdma *busdma;
45267fb10f3SMarcel Moolenaar 	struct proto_res *r;
4534f027abdSMarcel Moolenaar 	struct proto_softc *sc;
45467fb10f3SMarcel Moolenaar 	int error;
45567fb10f3SMarcel Moolenaar 
4564f027abdSMarcel Moolenaar 	sc = cdev->si_drv1;
45767fb10f3SMarcel Moolenaar 	r = cdev->si_drv2;
45867fb10f3SMarcel Moolenaar 
45967fb10f3SMarcel Moolenaar 	error = 0;
46067fb10f3SMarcel Moolenaar 	switch (cmd) {
46167fb10f3SMarcel Moolenaar 	case PROTO_IOC_REGION:
4625dcca8e8SMarcel Moolenaar 		if (r->r_type == PROTO_RES_BUSDMA) {
4635dcca8e8SMarcel Moolenaar 			error = EINVAL;
4645dcca8e8SMarcel Moolenaar 			break;
4655dcca8e8SMarcel Moolenaar 		}
46667fb10f3SMarcel Moolenaar 		region = (struct proto_ioc_region *)data;
46767fb10f3SMarcel Moolenaar 		region->size = r->r_size;
46867fb10f3SMarcel Moolenaar 		if (r->r_type == PROTO_RES_PCICFG)
46967fb10f3SMarcel Moolenaar 			region->address = 0;
47067fb10f3SMarcel Moolenaar 		else
4714f027abdSMarcel Moolenaar 			region->address = rman_get_start(r->r_d.res);
4724f027abdSMarcel Moolenaar 		break;
4734f027abdSMarcel Moolenaar 	case PROTO_IOC_BUSDMA:
4745dcca8e8SMarcel Moolenaar 		if (r->r_type != PROTO_RES_BUSDMA) {
4755dcca8e8SMarcel Moolenaar 			error = EINVAL;
4765dcca8e8SMarcel Moolenaar 			break;
4775dcca8e8SMarcel Moolenaar 		}
4784f027abdSMarcel Moolenaar 		busdma = (struct proto_ioc_busdma *)data;
47989abdea8SMarcel Moolenaar 		error = proto_busdma_ioctl(sc, r->r_d.busdma, busdma, td);
48067fb10f3SMarcel Moolenaar 		break;
48167fb10f3SMarcel Moolenaar 	default:
48267fb10f3SMarcel Moolenaar 		error = ENOIOCTL;
48367fb10f3SMarcel Moolenaar 		break;
48467fb10f3SMarcel Moolenaar 	}
48567fb10f3SMarcel Moolenaar 	return (error);
48667fb10f3SMarcel Moolenaar }
48767fb10f3SMarcel Moolenaar 
48867fb10f3SMarcel Moolenaar static int
proto_mmap(struct cdev * cdev,vm_ooffset_t offset,vm_paddr_t * paddr,int prot,vm_memattr_t * memattr)48967fb10f3SMarcel Moolenaar proto_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
49067fb10f3SMarcel Moolenaar     int prot, vm_memattr_t *memattr)
49167fb10f3SMarcel Moolenaar {
49267fb10f3SMarcel Moolenaar 	struct proto_res *r;
49367fb10f3SMarcel Moolenaar 
49467fb10f3SMarcel Moolenaar 	if (offset & PAGE_MASK)
49567fb10f3SMarcel Moolenaar 		return (EINVAL);
49667fb10f3SMarcel Moolenaar 	if (prot & PROT_EXEC)
49767fb10f3SMarcel Moolenaar 		return (EACCES);
498cff0f135SMarcel Moolenaar 
499cff0f135SMarcel Moolenaar 	r = cdev->si_drv2;
500cff0f135SMarcel Moolenaar 
501cff0f135SMarcel Moolenaar 	switch (r->r_type) {
502cff0f135SMarcel Moolenaar 	case SYS_RES_MEMORY:
50367fb10f3SMarcel Moolenaar 		if (offset >= r->r_size)
50467fb10f3SMarcel Moolenaar 			return (EINVAL);
5054f027abdSMarcel Moolenaar 		*paddr = rman_get_start(r->r_d.res) + offset;
50667fb10f3SMarcel Moolenaar 		*memattr = VM_MEMATTR_UNCACHEABLE;
507cff0f135SMarcel Moolenaar 		break;
508cff0f135SMarcel Moolenaar 	case PROTO_RES_BUSDMA:
509cff0f135SMarcel Moolenaar 		if (!proto_busdma_mmap_allowed(r->r_d.busdma, offset))
510cff0f135SMarcel Moolenaar 			return (EINVAL);
511cff0f135SMarcel Moolenaar 		*paddr = offset;
512cff0f135SMarcel Moolenaar 		break;
513cff0f135SMarcel Moolenaar 	default:
514cff0f135SMarcel Moolenaar 		return (ENXIO);
515cff0f135SMarcel Moolenaar 	}
51667fb10f3SMarcel Moolenaar 	return (0);
51767fb10f3SMarcel Moolenaar }
518