1 /* $NetBSD: irframe.c,v 1.9 2001/12/05 20:00:15 augustss 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 cdev_decl(irframe); 57 58 int irframe_match(struct device *parent, struct cfdata *match, void *aux); 59 void irframe_attach(struct device *parent, struct device *self, void *aux); 60 int irframe_activate(struct device *self, enum devact act); 61 int irframe_detach(struct device *self, int flags); 62 63 static int irf_reset_params(struct irframe_softc *sc); 64 65 #if NIRFRAME == 0 66 /* In case we just have tty attachment. */ 67 struct cfdriver irframe_cd = { 68 NULL, "irframe", DV_DULL 69 }; 70 #endif 71 72 struct cfattach irframe_ca = { 73 sizeof(struct irframe_softc), irframe_match, irframe_attach, 74 irframe_detach, irframe_activate 75 }; 76 77 extern struct cfattach irframe_ca; 78 extern struct cfdriver irframe_cd; 79 80 #define IRFRAMEUNIT(dev) (minor(dev)) 81 82 int 83 irframe_match(struct device *parent, struct cfdata *match, void *aux) 84 { 85 struct ir_attach_args *ia = aux; 86 87 return (ia->ia_type == IR_TYPE_IRFRAME); 88 } 89 90 void 91 irframe_attach(struct device *parent, struct device *self, void *aux) 92 { 93 struct irframe_softc *sc = (struct irframe_softc *)self; 94 struct ir_attach_args *ia = aux; 95 const char *delim; 96 int speeds = 0; 97 98 sc->sc_methods = ia->ia_methods; 99 sc->sc_handle = ia->ia_handle; 100 101 #ifdef DIAGNOSTIC 102 if (sc->sc_methods->im_read == NULL || 103 sc->sc_methods->im_write == NULL || 104 sc->sc_methods->im_poll == NULL || 105 sc->sc_methods->im_set_params == NULL || 106 sc->sc_methods->im_get_speeds == NULL || 107 sc->sc_methods->im_get_turnarounds == NULL) 108 panic("%s: missing methods\n", sc->sc_dev.dv_xname); 109 #endif 110 111 (void)sc->sc_methods->im_get_speeds(sc->sc_handle, &speeds); 112 delim = ":"; 113 if (speeds & IRDA_SPEEDS_SIR) { 114 printf("%s SIR", delim); 115 delim = ","; 116 } 117 if (speeds & IRDA_SPEEDS_MIR) { 118 printf("%s MIR", delim); 119 delim = ","; 120 } 121 if (speeds & IRDA_SPEEDS_FIR) { 122 printf("%s FIR", delim); 123 delim = ","; 124 } 125 if (speeds & IRDA_SPEEDS_VFIR) { 126 printf("%s VFIR", delim); 127 delim = ","; 128 } 129 printf("\n"); 130 } 131 132 int 133 irframe_activate(struct device *self, enum devact act) 134 { 135 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/ 136 137 switch (act) { 138 case DVACT_ACTIVATE: 139 return (EOPNOTSUPP); 140 break; 141 142 case DVACT_DEACTIVATE: 143 break; 144 } 145 return (0); 146 } 147 148 int 149 irframe_detach(struct device *self, int flags) 150 { 151 /*struct irframe_softc *sc = (struct irframe_softc *)self;*/ 152 int maj, mn; 153 154 /* locate the major number */ 155 for (maj = 0; maj < nchrdev; maj++) 156 if (cdevsw[maj].d_open == irframeopen) 157 break; 158 159 /* Nuke the vnodes for any open instances (calls close). */ 160 mn = self->dv_unit; 161 vdevgone(maj, mn, mn, VCHR); 162 163 return (0); 164 } 165 166 int 167 irframeopen(dev_t dev, int flag, int mode, struct proc *p) 168 { 169 struct irframe_softc *sc; 170 int error; 171 172 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev)); 173 if (sc == NULL) 174 return (ENXIO); 175 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) 176 return (EIO); 177 if (sc->sc_open) 178 return (EBUSY); 179 if (sc->sc_methods->im_open != NULL) { 180 error = sc->sc_methods->im_open(sc->sc_handle, flag, mode, p); 181 if (error) 182 return (error); 183 } 184 sc->sc_open = 1; 185 (void)irf_reset_params(sc); 186 return (0); 187 } 188 189 int 190 irframeclose(dev_t dev, int flag, int mode, struct proc *p) 191 { 192 struct irframe_softc *sc; 193 int error; 194 195 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev)); 196 if (sc == NULL) 197 return (ENXIO); 198 if (sc->sc_methods->im_close != NULL) 199 error = sc->sc_methods->im_close(sc->sc_handle, flag, mode, p); 200 else 201 error = 0; 202 sc->sc_open = 0; 203 return (error); 204 } 205 206 int 207 irframeread(dev_t dev, struct uio *uio, int flag) 208 { 209 struct irframe_softc *sc; 210 211 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev)); 212 if (sc == NULL) 213 return (ENXIO); 214 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) 215 return (EIO); 216 return (sc->sc_methods->im_read(sc->sc_handle, uio, flag)); 217 } 218 219 int 220 irframewrite(dev_t dev, struct uio *uio, int flag) 221 { 222 struct irframe_softc *sc; 223 224 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev)); 225 if (sc == NULL) 226 return (ENXIO); 227 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) 228 return (EIO); 229 return (sc->sc_methods->im_write(sc->sc_handle, uio, flag)); 230 } 231 232 int 233 irf_reset_params(struct irframe_softc *sc) 234 { 235 struct irda_params params; 236 237 params.speed = IRDA_DEFAULT_SPEED; 238 params.ebofs = IRDA_DEFAULT_EBOFS; 239 params.maxsize = IRDA_DEFAULT_SIZE; 240 return (sc->sc_methods->im_set_params(sc->sc_handle, ¶ms)); 241 } 242 243 int 244 irframeioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 245 { 246 struct irframe_softc *sc; 247 void *vaddr = addr; 248 int error; 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) 254 return (EIO); 255 256 switch (cmd) { 257 case FIONBIO: 258 /* All handled in the upper FS layer. */ 259 error = 0; 260 break; 261 262 case IRDA_SET_PARAMS: 263 error = sc->sc_methods->im_set_params(sc->sc_handle, vaddr); 264 break; 265 266 case IRDA_RESET_PARAMS: 267 error = irf_reset_params(sc); 268 break; 269 270 case IRDA_GET_SPEEDMASK: 271 error = sc->sc_methods->im_get_speeds(sc->sc_handle, vaddr); 272 break; 273 274 case IRDA_GET_TURNAROUNDMASK: 275 error = sc->sc_methods->im_get_turnarounds(sc->sc_handle,vaddr); 276 break; 277 278 default: 279 error = EINVAL; 280 break; 281 } 282 return (error); 283 } 284 285 int 286 irframepoll(dev_t dev, int events, struct proc *p) 287 { 288 struct irframe_softc *sc; 289 290 sc = device_lookup(&irframe_cd, IRFRAMEUNIT(dev)); 291 if (sc == NULL) 292 return (ENXIO); 293 if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0) 294 return (EIO); 295 296 return (sc->sc_methods->im_poll(sc->sc_handle, events, p)); 297 } 298 299 /*********/ 300 301 302 struct device * 303 irframe_alloc(size_t size, const struct irframe_methods *m, void *h) 304 { 305 struct cfdriver *cd = &irframe_cd; 306 struct device *dev; 307 struct ir_attach_args ia; 308 int unit; 309 310 for (unit = 0; unit < cd->cd_ndevs; unit++) 311 if (cd->cd_devs[unit] == NULL) 312 break; 313 dev = malloc(size, M_DEVBUF, M_WAITOK); 314 memset(dev, 0, size); 315 snprintf(dev->dv_xname, sizeof dev->dv_xname, "irframe%d", unit); 316 dev->dv_unit = unit; 317 dev->dv_flags = DVF_ACTIVE; /* always initially active */ 318 319 config_makeroom(unit, cd); 320 cd->cd_devs[unit] = dev; 321 322 ia.ia_methods = m; 323 ia.ia_handle = h; 324 printf("%s", dev->dv_xname); 325 irframe_attach(NULL, dev, &ia); 326 327 return (dev); 328 } 329 330 void 331 irframe_dealloc(struct device *dev) 332 { 333 struct cfdriver *cd = &irframe_cd; 334 int unit; 335 336 for (unit = 0; unit < cd->cd_ndevs; unit++) { 337 if (cd->cd_devs[unit] == dev) { 338 cd->cd_devs[unit] = NULL; 339 free(dev, M_DEVBUF); 340 return; 341 } 342 } 343 panic("irframe_dealloc: device not found\n"); 344 } 345