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