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