irframe.c revision 1.12 1 /* $NetBSD: irframe.c,v 1.12 2001/12/13 17:15:09 augustss Exp $ */
2
3 /*
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart (at) augustsson.net).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include "irframe.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/ioctl.h>
44 #include <sys/kernel.h>
45 #include <sys/device.h>
46 #include <sys/conf.h>
47 #include <sys/malloc.h>
48 #include <sys/poll.h>
49 #include <sys/select.h>
50 #include <sys/vnode.h>
51
52 #include <dev/ir/ir.h>
53 #include <dev/ir/irdaio.h>
54 #include <dev/ir/irframevar.h>
55
56 #ifdef IRFRAME_DEBUG
57 #define DPRINTF(x) if (irframedebug) printf x
58 #define Static
59 int irframedebug = 0;
60 #else
61 #define DPRINTF(x)
62 #define Static static
63 #endif
64
65 cdev_decl(irframe);
66
67 int irframe_match(struct device *parent, struct cfdata *match, void *aux);
68 void irframe_attach(struct device *parent, struct device *self, void *aux);
69 int irframe_activate(struct device *self, enum devact act);
70 int irframe_detach(struct device *self, int flags);
71
72 Static int irf_reset_params(struct irframe_softc *sc);
73
74 #if NIRFRAME == 0
75 /* In case we just have tty attachment. */
76 struct cfdriver irframe_cd = {
77 NULL, "irframe", DV_DULL
78 };
79 #endif
80
81 struct cfattach irframe_ca = {
82 sizeof(struct irframe_softc), irframe_match, irframe_attach,
83 irframe_detach, irframe_activate
84 };
85
86 extern struct cfattach irframe_ca;
87 extern struct cfdriver irframe_cd;
88
89 #define IRFRAMEUNIT(dev) (minor(dev))
90
91 int
92 irframe_match(struct device *parent, struct cfdata *match, void *aux)
93 {
94 struct ir_attach_args *ia = aux;
95
96 return (ia->ia_type == IR_TYPE_IRFRAME);
97 }
98
99 void
100 irframe_attach(struct device *parent, struct device *self, void *aux)
101 {
102 struct irframe_softc *sc = (struct irframe_softc *)self;
103 struct ir_attach_args *ia = aux;
104 const char *delim;
105 int speeds = 0;
106
107 sc->sc_methods = ia->ia_methods;
108 sc->sc_handle = ia->ia_handle;
109
110 #ifdef DIAGNOSTIC
111 if (sc->sc_methods->im_read == NULL ||
112 sc->sc_methods->im_write == NULL ||
113 sc->sc_methods->im_poll == NULL ||
114 sc->sc_methods->im_set_params == NULL ||
115 sc->sc_methods->im_get_speeds == NULL ||
116 sc->sc_methods->im_get_turnarounds == NULL)
117 panic("%s: missing methods\n", sc->sc_dev.dv_xname);
118 #endif
119
120 (void)sc->sc_methods->im_get_speeds(sc->sc_handle, &speeds);
121 sc->sc_speedmask = speeds;
122 delim = ":";
123 if (speeds & IRDA_SPEEDS_SIR) {
124 printf("%s SIR", delim);
125 delim = ",";
126 }
127 if (speeds & IRDA_SPEEDS_MIR) {
128 printf("%s MIR", delim);
129 delim = ",";
130 }
131 if (speeds & IRDA_SPEEDS_FIR) {
132 printf("%s FIR", delim);
133 delim = ",";
134 }
135 if (speeds & IRDA_SPEEDS_VFIR) {
136 printf("%s VFIR", delim);
137 delim = ",";
138 }
139 printf("\n");
140 }
141
142 int
143 irframe_activate(struct device *self, enum devact act)
144 {
145 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/
146
147 switch (act) {
148 case DVACT_ACTIVATE:
149 return (EOPNOTSUPP);
150 break;
151
152 case DVACT_DEACTIVATE:
153 break;
154 }
155 return (0);
156 }
157
158 int
159 irframe_detach(struct device *self, int flags)
160 {
161 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/
162 int maj, mn;
163
164 /* locate the major number */
165 for (maj = 0; maj < nchrdev; maj++)
166 if (cdevsw[maj].d_open == irframeopen)
167 break;
168
169 /* Nuke the vnodes for any open instances (calls close). */
170 mn = self->dv_unit;
171 vdevgone(maj, mn, mn, VCHR);
172
173 return (0);
174 }
175
176 int
177 irframeopen(dev_t dev, int flag, int mode, struct proc *p)
178 {
179 struct irframe_softc *sc;
180 int error;
181
182 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
183 if (sc == NULL)
184 return (ENXIO);
185 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
186 return (EIO);
187 if (sc->sc_open)
188 return (EBUSY);
189 if (sc->sc_methods->im_open != NULL) {
190 error = sc->sc_methods->im_open(sc->sc_handle, flag, mode, p);
191 if (error)
192 return (error);
193 }
194 sc->sc_open = 1;
195 #ifdef DIAGNOSTIC
196 sc->sc_speed = IRDA_DEFAULT_SPEED;
197 #endif
198 (void)irf_reset_params(sc);
199 return (0);
200 }
201
202 int
203 irframeclose(dev_t dev, int flag, int mode, struct proc *p)
204 {
205 struct irframe_softc *sc;
206 int error;
207
208 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
209 if (sc == NULL)
210 return (ENXIO);
211 if (sc->sc_methods->im_close != NULL)
212 error = sc->sc_methods->im_close(sc->sc_handle, flag, mode, p);
213 else
214 error = 0;
215 sc->sc_open = 0;
216 return (error);
217 }
218
219 int
220 irframeread(dev_t dev, struct uio *uio, int flag)
221 {
222 struct irframe_softc *sc;
223
224 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
225 if (sc == NULL)
226 return (ENXIO);
227 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
228 return (EIO);
229 if (uio->uio_resid < sc->sc_params.maxsize) {
230 #ifdef DIAGNOSTIC
231 printf("irframeread: short read %d < %d\n", uio->uio_resid,
232 sc->sc_params.maxsize);
233 #endif
234 return (EINVAL);
235 }
236 return (sc->sc_methods->im_read(sc->sc_handle, uio, flag));
237 }
238
239 int
240 irframewrite(dev_t dev, struct uio *uio, int flag)
241 {
242 struct irframe_softc *sc;
243
244 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
245 if (sc == NULL)
246 return (ENXIO);
247 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
248 return (EIO);
249 if (uio->uio_resid > sc->sc_params.maxsize) {
250 #ifdef DIAGNOSTIC
251 printf("irframeread: long write %d > %d\n", uio->uio_resid,
252 sc->sc_params.maxsize);
253 #endif
254 return (EINVAL);
255 }
256 return (sc->sc_methods->im_write(sc->sc_handle, uio, flag));
257 }
258
259 int
260 irf_reset_params(struct irframe_softc *sc)
261 {
262 struct irda_params params;
263 int error;
264
265 params.speed = IRDA_DEFAULT_SPEED;
266 params.ebofs = IRDA_DEFAULT_EBOFS;
267 params.maxsize = IRDA_DEFAULT_SIZE;
268 error = sc->sc_methods->im_set_params(sc->sc_handle, ¶ms);
269 if (!error)
270 sc->sc_params = params;
271 return (error);
272 }
273
274 int
275 irframeioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
276 {
277 struct irframe_softc *sc;
278 void *vaddr = addr;
279 struct irda_params *parms = vaddr;
280 int error;
281
282 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
283 if (sc == NULL)
284 return (ENXIO);
285 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
286 return (EIO);
287
288 switch (cmd) {
289 case FIONBIO:
290 /* All handled in the upper FS layer. */
291 error = 0;
292 break;
293
294 case IRDA_SET_PARAMS:
295 DPRINTF(("irframeioctl: set params speed=%u ebofs=%u maxsize=%u\n", parms->speed, parms->ebofs, parms->maxsize));
296 #ifdef DIAGNOSTIC
297 if (parms->speed != sc->sc_speed) {
298 sc->sc_speed = parms->speed;
299 printf("%s: set speed %u\n", sc->sc_dev.dv_xname,
300 sc->sc_speed);
301 }
302 #endif
303 if (parms->maxsize > IRDA_MAX_FRAME_SIZE)
304 return (EINVAL);
305 if (parms->ebofs > IRDA_MAX_EBOFS)
306 return (EINVAL);
307 /* XXX check speed */
308 error = sc->sc_methods->im_set_params(sc->sc_handle, vaddr);
309 if (!error) {
310 sc->sc_params = *parms;
311 DPRINTF(("irframeioctl: ok\n"));
312 }
313 break;
314
315 case IRDA_RESET_PARAMS:
316 error = irf_reset_params(sc);
317 break;
318
319 case IRDA_GET_SPEEDMASK:
320 error = sc->sc_methods->im_get_speeds(sc->sc_handle, vaddr);
321 break;
322
323 case IRDA_GET_TURNAROUNDMASK:
324 error = sc->sc_methods->im_get_turnarounds(sc->sc_handle,vaddr);
325 break;
326
327 default:
328 error = EINVAL;
329 break;
330 }
331 return (error);
332 }
333
334 int
335 irframepoll(dev_t dev, int events, struct proc *p)
336 {
337 struct irframe_softc *sc;
338
339 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
340 if (sc == NULL)
341 return (ENXIO);
342 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
343 return (EIO);
344
345 return (sc->sc_methods->im_poll(sc->sc_handle, events, p));
346 }
347
348 /*********/
349
350
351 struct device *
352 irframe_alloc(size_t size, const struct irframe_methods *m, void *h)
353 {
354 struct cfdriver *cd = &irframe_cd;
355 struct device *dev;
356 struct ir_attach_args ia;
357 int unit;
358
359 for (unit = 0; unit < cd->cd_ndevs; unit++)
360 if (cd->cd_devs[unit] == NULL)
361 break;
362 dev = malloc(size, M_DEVBUF, M_WAITOK);
363 memset(dev, 0, size);
364 snprintf(dev->dv_xname, sizeof dev->dv_xname, "irframe%d", unit);
365 dev->dv_unit = unit;
366 dev->dv_flags = DVF_ACTIVE; /* always initially active */
367
368 config_makeroom(unit, cd);
369 cd->cd_devs[unit] = dev;
370
371 ia.ia_methods = m;
372 ia.ia_handle = h;
373 printf("%s", dev->dv_xname);
374 irframe_attach(NULL, dev, &ia);
375
376 return (dev);
377 }
378
379 void
380 irframe_dealloc(struct device *dev)
381 {
382 struct cfdriver *cd = &irframe_cd;
383 int unit;
384
385 for (unit = 0; unit < cd->cd_ndevs; unit++) {
386 if (cd->cd_devs[unit] == dev) {
387 cd->cd_devs[unit] = NULL;
388 free(dev, M_DEVBUF);
389 return;
390 }
391 }
392 panic("irframe_dealloc: device not found\n");
393 }
394