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