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