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