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