irframe.c revision 1.15 1 /* $NetBSD: irframe.c,v 1.15 2001/12/29 14:25:47 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_set_params(struct irframe_softc *sc, struct irda_params *p);
73 Static int irf_reset_params(struct irframe_softc *sc);
74
75 #if NIRFRAME == 0
76 /* In case we just have tty attachment. */
77 struct cfdriver irframe_cd = {
78 NULL, "irframe", DV_DULL
79 };
80 #endif
81
82 struct cfattach irframe_ca = {
83 sizeof(struct irframe_softc), irframe_match, irframe_attach,
84 irframe_detach, irframe_activate
85 };
86
87 extern struct cfattach irframe_ca;
88 extern struct cfdriver irframe_cd;
89
90 #define IRFRAMEUNIT(dev) (minor(dev))
91
92 int
93 irframe_match(struct device *parent, struct cfdata *match, void *aux)
94 {
95 struct ir_attach_args *ia = aux;
96
97 return (ia->ia_type == IR_TYPE_IRFRAME);
98 }
99
100 void
101 irframe_attach(struct device *parent, struct device *self, void *aux)
102 {
103 struct irframe_softc *sc = (struct irframe_softc *)self;
104 struct ir_attach_args *ia = aux;
105 const char *delim;
106 int speeds = 0;
107
108 sc->sc_methods = ia->ia_methods;
109 sc->sc_handle = ia->ia_handle;
110
111 #ifdef DIAGNOSTIC
112 if (sc->sc_methods->im_read == NULL ||
113 sc->sc_methods->im_write == NULL ||
114 sc->sc_methods->im_poll == NULL ||
115 sc->sc_methods->im_set_params == NULL ||
116 sc->sc_methods->im_get_speeds == NULL ||
117 sc->sc_methods->im_get_turnarounds == NULL)
118 panic("%s: missing methods\n", sc->sc_dev.dv_xname);
119 #endif
120
121 (void)sc->sc_methods->im_get_speeds(sc->sc_handle, &speeds);
122 sc->sc_speedmask = speeds;
123 delim = ":";
124 if (speeds & IRDA_SPEEDS_SIR) {
125 printf("%s SIR", delim);
126 delim = ",";
127 }
128 if (speeds & IRDA_SPEEDS_MIR) {
129 printf("%s MIR", delim);
130 delim = ",";
131 }
132 if (speeds & IRDA_SPEEDS_FIR) {
133 printf("%s FIR", delim);
134 delim = ",";
135 }
136 if (speeds & IRDA_SPEEDS_VFIR) {
137 printf("%s VFIR", delim);
138 delim = ",";
139 }
140 printf("\n");
141 }
142
143 int
144 irframe_activate(struct device *self, enum devact act)
145 {
146 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/
147
148 switch (act) {
149 case DVACT_ACTIVATE:
150 return (EOPNOTSUPP);
151 break;
152
153 case DVACT_DEACTIVATE:
154 break;
155 }
156 return (0);
157 }
158
159 int
160 irframe_detach(struct device *self, int flags)
161 {
162 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/
163 int maj, mn;
164
165 /* XXX needs reference count */
166
167 /* locate the major number */
168 for (maj = 0; maj < nchrdev; maj++)
169 if (cdevsw[maj].d_open == irframeopen)
170 break;
171
172 /* Nuke the vnodes for any open instances (calls close). */
173 mn = self->dv_unit;
174 vdevgone(maj, mn, mn, VCHR);
175
176 return (0);
177 }
178
179 int
180 irframeopen(dev_t dev, int flag, int mode, struct proc *p)
181 {
182 struct irframe_softc *sc;
183 int error;
184
185 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
186 if (sc == NULL)
187 return (ENXIO);
188 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
189 return (EIO);
190 if (sc->sc_open)
191 return (EBUSY);
192 if (sc->sc_methods->im_open != NULL) {
193 error = sc->sc_methods->im_open(sc->sc_handle, flag, mode, p);
194 if (error)
195 return (error);
196 }
197 sc->sc_open = 1;
198 #ifdef DIAGNOSTIC
199 sc->sc_speed = IRDA_DEFAULT_SPEED;
200 #endif
201 (void)irf_reset_params(sc);
202 return (0);
203 }
204
205 int
206 irframeclose(dev_t dev, int flag, int mode, struct proc *p)
207 {
208 struct irframe_softc *sc;
209 int error;
210
211 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
212 if (sc == NULL)
213 return (ENXIO);
214 sc->sc_open = 0;
215 if (sc->sc_methods->im_close != NULL)
216 error = sc->sc_methods->im_close(sc->sc_handle, flag, mode, p);
217 else
218 error = 0;
219 return (error);
220 }
221
222 int
223 irframeread(dev_t dev, struct uio *uio, int flag)
224 {
225 struct irframe_softc *sc;
226
227 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
228 if (sc == NULL)
229 return (ENXIO);
230 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
231 return (EIO);
232 if (uio->uio_resid < sc->sc_params.maxsize) {
233 #ifdef DIAGNOSTIC
234 printf("irframeread: short read %d < %d\n", uio->uio_resid,
235 sc->sc_params.maxsize);
236 #endif
237 return (EINVAL);
238 }
239 return (sc->sc_methods->im_read(sc->sc_handle, uio, flag));
240 }
241
242 int
243 irframewrite(dev_t dev, struct uio *uio, int flag)
244 {
245 struct irframe_softc *sc;
246
247 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
248 if (sc == NULL)
249 return (ENXIO);
250 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
251 return (EIO);
252 if (uio->uio_resid > sc->sc_params.maxsize) {
253 #ifdef DIAGNOSTIC
254 printf("irframeread: long write %d > %d\n", uio->uio_resid,
255 sc->sc_params.maxsize);
256 #endif
257 return (EINVAL);
258 }
259 return (sc->sc_methods->im_write(sc->sc_handle, uio, flag));
260 }
261
262 int
263 irf_set_params(struct irframe_softc *sc, struct irda_params *p)
264 {
265 int error;
266
267 DPRINTF(("irf_set_params: set params speed=%u ebofs=%u maxsize=%u "
268 "speedmask=0x%x\n", p->speed, p->ebofs, p->maxsize,
269 sc->sc_speedmask));
270
271 if (p->maxsize > IRDA_MAX_FRAME_SIZE) {
272 #ifdef IRFRAME_DEBUG
273 printf("irf_set_params: bad maxsize=%u\n", p->maxsize);
274 #endif
275 return (EINVAL);
276 }
277
278 if (p->ebofs > IRDA_MAX_EBOFS) {
279 #ifdef IRFRAME_DEBUG
280 printf("irf_set_params: bad maxsize=%u\n", p->maxsize);
281 #endif
282 return (EINVAL);
283 }
284
285 #define CONC(x,y) x##y
286 #define CASE(s) case s: if (!(sc->sc_speedmask & CONC(IRDA_SPEED_,s))) return (EINVAL); break
287 switch (p->speed) {
288 CASE(2400);
289 CASE(9600);
290 CASE(19200);
291 CASE(38400);
292 CASE(57600);
293 CASE(115200);
294 CASE(576000);
295 CASE(1152000);
296 CASE(4000000);
297 CASE(16000000);
298 default: return (EINVAL);
299 }
300 #undef CONC
301 #undef CASE
302
303 error = sc->sc_methods->im_set_params(sc->sc_handle, p);
304 if (!error) {
305 sc->sc_params = *p;
306 DPRINTF(("irf_set_params: ok\n"));
307 #ifdef DIAGNOSTIC
308 if (p->speed != sc->sc_speed) {
309 sc->sc_speed = p->speed;
310 printf("%s: set speed %u\n", sc->sc_dev.dv_xname,
311 sc->sc_speed);
312 }
313 #endif
314 } else {
315 #ifdef IRFRAME_DEBUG
316 printf("irf_set_params: error=%d\n", error);
317 #endif
318 }
319 return (error);
320 }
321
322 int
323 irf_reset_params(struct irframe_softc *sc)
324 {
325 struct irda_params params;
326
327 params.speed = IRDA_DEFAULT_SPEED;
328 params.ebofs = IRDA_DEFAULT_EBOFS;
329 params.maxsize = IRDA_DEFAULT_SIZE;
330 return (irf_set_params(sc, ¶ms));
331 }
332
333 int
334 irframeioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
335 {
336 struct irframe_softc *sc;
337 void *vaddr = addr;
338 int error;
339
340 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
341 if (sc == NULL)
342 return (ENXIO);
343 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
344 return (EIO);
345
346 switch (cmd) {
347 case FIONBIO:
348 /* All handled in the upper FS layer. */
349 error = 0;
350 break;
351
352 case IRDA_SET_PARAMS:
353 error = irf_set_params(sc, vaddr);
354 break;
355
356 case IRDA_RESET_PARAMS:
357 error = irf_reset_params(sc);
358 break;
359
360 case IRDA_GET_SPEEDMASK:
361 error = sc->sc_methods->im_get_speeds(sc->sc_handle, vaddr);
362 break;
363
364 case IRDA_GET_TURNAROUNDMASK:
365 error = sc->sc_methods->im_get_turnarounds(sc->sc_handle,vaddr);
366 break;
367
368 default:
369 error = EINVAL;
370 break;
371 }
372 return (error);
373 }
374
375 int
376 irframepoll(dev_t dev, int events, struct proc *p)
377 {
378 struct irframe_softc *sc;
379
380 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev));
381 if (sc == NULL)
382 return (ENXIO);
383 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 || !sc->sc_open)
384 return (EIO);
385
386 return (sc->sc_methods->im_poll(sc->sc_handle, events, p));
387 }
388
389 /*********/
390
391
392 struct device *
393 irframe_alloc(size_t size, const struct irframe_methods *m, void *h)
394 {
395 struct cfdriver *cd = &irframe_cd;
396 struct device *dev;
397 struct ir_attach_args ia;
398 int unit;
399
400 for (unit = 0; unit < cd->cd_ndevs; unit++)
401 if (cd->cd_devs[unit] == NULL)
402 break;
403 dev = malloc(size, M_DEVBUF, M_WAITOK);
404 memset(dev, 0, size);
405 snprintf(dev->dv_xname, sizeof dev->dv_xname, "irframe%d", unit);
406 dev->dv_unit = unit;
407 dev->dv_flags = DVF_ACTIVE; /* always initially active */
408
409 config_makeroom(unit, cd);
410 cd->cd_devs[unit] = dev;
411
412 ia.ia_methods = m;
413 ia.ia_handle = h;
414 printf("%s", dev->dv_xname);
415 irframe_attach(NULL, dev, &ia);
416
417 return (dev);
418 }
419
420 void
421 irframe_dealloc(struct device *dev)
422 {
423 struct cfdriver *cd = &irframe_cd;
424 int unit;
425
426 for (unit = 0; unit < cd->cd_ndevs; unit++) {
427 if (cd->cd_devs[unit] == dev) {
428 cd->cd_devs[unit] = NULL;
429 free(dev, M_DEVBUF);
430 return;
431 }
432 }
433 panic("irframe_dealloc: device not found\n");
434 }
435