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