]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pccard/pccard_device.c
Regularize my copyright notice
[FreeBSD/FreeBSD.git] / sys / dev / pccard / pccard_device.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005 M. Warner Losh <imp@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    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/conf.h>
34 #include <sys/malloc.h>
35 #include <sys/systm.h>
36 #include <sys/uio.h>
37
38 #include <sys/bus.h>
39 #include <machine/bus.h>
40 #include <sys/rman.h>
41 #include <machine/resource.h>
42
43 #include <dev/pccard/pccardreg.h>
44 #include <dev/pccard/pccardvar.h>
45 #include <dev/pccard/pccardvarp.h>
46 #include <dev/pccard/pccard_cis.h>
47
48 static  d_open_t        pccard_open;
49 static  d_close_t       pccard_close;
50 static  d_read_t        pccard_read;
51 static  d_ioctl_t       pccard_ioctl;
52
53 static struct cdevsw pccard_cdevsw = {
54         .d_version =    D_VERSION,
55         .d_open =       pccard_open,
56         .d_close =      pccard_close,
57         .d_read =       pccard_read,
58         .d_ioctl =      pccard_ioctl,
59         .d_name =       "pccard"
60 };
61
62 int
63 pccard_device_create(struct pccard_softc *sc)
64 {
65         uint32_t minor;
66
67         minor = device_get_unit(sc->dev) << 16;
68         sc->cisdev = make_dev(&pccard_cdevsw, minor, 0, 0, 0666,
69             "pccard%u.cis", device_get_unit(sc->dev));
70         sc->cisdev->si_drv1 = sc;
71         return (0);
72 }
73
74 int
75 pccard_device_destroy(struct pccard_softc *sc)
76 {
77         if (sc->cisdev)
78                 destroy_dev(sc->cisdev);
79         return (0);
80 }
81
82 static int
83 pccard_build_cis(const struct pccard_tuple *tuple, void *argp)
84 {
85         struct cis_buffer *cis;
86         int i;
87         uint8_t ch;
88
89         cis = (struct cis_buffer *)argp;
90         /*
91          * CISTPL_END is a special case, it has no length field.
92          */
93         if (tuple->code == CISTPL_END) {
94                 if (cis->len + 1 > sizeof(cis->buffer))
95                         return (ENOSPC);
96                 cis->buffer[cis->len++] = tuple->code;
97                 return (0);
98         }
99         if (cis->len + 2 + tuple->length > sizeof(cis->buffer))
100                 return (ENOSPC);
101         cis->buffer[cis->len++] = tuple->code;
102         cis->buffer[cis->len++] = tuple->length;
103         for (i = 0; i < tuple->length; i++) {
104                 ch = pccard_tuple_read_1(tuple, i);
105                 cis->buffer[cis->len++] = ch;
106         }
107         return (0);
108 }
109
110 static  int
111 pccard_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
112 {
113         device_t parent, child;
114         device_t *kids;
115         int cnt, err;
116         struct pccard_softc *sc;
117
118         sc = dev->si_drv1;
119         if (sc->cis_open)
120                 return (EBUSY);
121         parent = sc->dev;
122         err = device_get_children(parent, &kids, &cnt);
123         if (err)
124                 return err;
125         if (cnt == 0) {
126                 free(kids, M_TEMP);
127                 sc->cis_open++;
128                 sc->cis = NULL;
129                 return (0);
130         }
131         child = kids[0];
132         free(kids, M_TEMP);
133         sc->cis = malloc(sizeof(*sc->cis), M_TEMP, M_ZERO | M_WAITOK);
134         err = pccard_scan_cis(parent, child, pccard_build_cis, sc->cis);
135         if (err) {
136                 free(sc->cis, M_TEMP);
137                 sc->cis = NULL;
138                 return (err);
139         }
140         sc->cis_open++;
141         return (0);
142 }
143
144 static  int
145 pccard_close(struct cdev *dev, int fflags, int devtype, struct thread *td)
146 {
147         struct pccard_softc *sc;
148
149         sc = dev->si_drv1;
150         free(sc->cis, M_TEMP);
151         sc->cis = NULL;
152         sc->cis_open = 0;
153         return (0);
154 }
155
156 static  int
157 pccard_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
158     struct thread *td)
159 {
160         return (ENOTTY);
161 }
162
163 static  int
164 pccard_read(struct cdev *dev, struct uio *uio, int ioflag)
165 {
166         struct pccard_softc *sc;
167
168         sc = dev->si_drv1;
169         /* EOF */
170         if (sc->cis == NULL || uio->uio_offset > sc->cis->len)
171                 return (0);
172         return (uiomove(sc->cis->buffer + uio->uio_offset,
173           MIN(uio->uio_resid, sc->cis->len - uio->uio_offset), uio));
174 }