1 /*- 2 * Copyright (c) 1998, 2001 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/dev/iicbus/iic.c,v 1.43 2009/01/26 13:53:39 raj Exp $ 27 * $DragonFly: src/sys/bus/iicbus/iic.c,v 1.10 2006/09/10 01:26:32 dillon Exp $ 28 * 29 */ 30 #include <sys/param.h> 31 #include <sys/buf.h> 32 #include <sys/bus.h> 33 #include <sys/conf.h> 34 #include <sys/fcntl.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/systm.h> 39 #include <sys/uio.h> 40 41 #include <bus/iicbus/iiconf.h> 42 #include <bus/iicbus/iicbus.h> 43 #include <bus/iicbus/iic.h> 44 45 #include "iicbus_if.h" 46 47 #define BUFSIZE 1024 48 49 struct iic_softc { 50 51 device_t sc_dev; 52 u_char sc_addr; /* 7 bit address on iicbus */ 53 int sc_count; /* >0 if device opened */ 54 55 char sc_buffer[BUFSIZE]; /* output buffer */ 56 char sc_inbuf[BUFSIZE]; /* input buffer */ 57 58 cdev_t sc_devnode; 59 }; 60 61 #define IIC_LOCK(sc) 62 #define IIC_UNLOCK(sc) 63 64 static int iic_probe(device_t); 65 static int iic_attach(device_t); 66 static int iic_detach(device_t); 67 static void iic_identify(driver_t *driver, device_t parent); 68 69 static devclass_t iic_devclass; 70 71 static device_method_t iic_methods[] = { 72 /* device interface */ 73 DEVMETHOD(device_identify, iic_identify), 74 DEVMETHOD(device_probe, iic_probe), 75 DEVMETHOD(device_attach, iic_attach), 76 DEVMETHOD(device_detach, iic_detach), 77 78 /* iicbus interface */ 79 DEVMETHOD(iicbus_intr, iicbus_generic_intr), 80 81 { 0, 0 } 82 }; 83 84 static driver_t iic_driver = { 85 "iic", 86 iic_methods, 87 sizeof(struct iic_softc), 88 }; 89 90 static d_open_t iicopen; 91 static d_close_t iicclose; 92 static d_write_t iicwrite; 93 static d_read_t iicread; 94 static d_ioctl_t iicioctl; 95 96 static struct dev_ops iic_ops = { 97 { "iic", 0, 0 }, 98 .d_open = iicopen, 99 .d_close = iicclose, 100 .d_read = iicread, 101 .d_write = iicwrite, 102 .d_ioctl = iicioctl, 103 }; 104 105 static void 106 iic_identify(driver_t *driver, device_t parent) 107 { 108 109 if (device_find_child(parent, "iic", -1) == NULL) 110 BUS_ADD_CHILD(parent, parent, 0, "iic", -1); 111 } 112 113 static int 114 iic_probe(device_t dev) 115 { 116 if (iicbus_get_addr(dev) > 0) 117 return (ENXIO); 118 119 device_set_desc(dev, "I2C generic I/O"); 120 121 return (0); 122 } 123 124 static int 125 iic_attach(device_t dev) 126 { 127 struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev); 128 129 sc->sc_devnode = make_dev(&iic_ops, device_get_unit(dev), 130 UID_ROOT, GID_WHEEL, 131 0600, "iic%d", device_get_unit(dev)); 132 if (sc->sc_devnode == NULL) { 133 device_printf(dev, "failed to create character device\n"); 134 return (ENXIO); 135 } 136 sc->sc_devnode->si_drv1 = sc; 137 138 return (0); 139 } 140 141 static int 142 iic_detach(device_t dev) 143 { 144 struct iic_softc *sc = (struct iic_softc *)device_get_softc(dev); 145 146 if (sc->sc_devnode) 147 dev_ops_remove_minor(&iic_ops, device_get_unit(dev)); 148 149 return (0); 150 } 151 152 static int 153 iicopen(struct dev_open_args *ap) 154 { 155 cdev_t dev = ap->a_head.a_dev; 156 struct iic_softc *sc = dev->si_drv1; 157 158 IIC_LOCK(sc); 159 if (sc->sc_count > 0) { 160 IIC_UNLOCK(sc); 161 return (EBUSY); 162 } 163 164 sc->sc_count++; 165 IIC_UNLOCK(sc); 166 167 return (0); 168 } 169 170 static int 171 iicclose(struct dev_close_args *ap) 172 { 173 cdev_t dev = ap->a_head.a_dev; 174 struct iic_softc *sc = dev->si_drv1; 175 176 IIC_LOCK(sc); 177 if (!sc->sc_count) { 178 /* XXX: I don't think this can happen. */ 179 IIC_UNLOCK(sc); 180 return (EINVAL); 181 } 182 183 sc->sc_count--; 184 185 if (sc->sc_count < 0) 186 panic("%s: iic_count < 0!", __func__); 187 IIC_UNLOCK(sc); 188 189 return (0); 190 } 191 192 static int 193 iicwrite(struct dev_write_args *ap) 194 { 195 cdev_t dev = ap->a_head.a_dev; 196 struct uio *uio = ap->a_uio; 197 struct iic_softc *sc = dev->si_drv1; 198 device_t iicdev = sc->sc_dev; 199 int sent, error, count; 200 201 IIC_LOCK(sc); 202 if (!sc->sc_addr) { 203 IIC_UNLOCK(sc); 204 return (EINVAL); 205 } 206 207 if (sc->sc_count == 0) { 208 /* XXX: I don't think this can happen. */ 209 IIC_UNLOCK(sc); 210 return (EINVAL); 211 } 212 213 error = iicbus_request_bus(device_get_parent(iicdev), iicdev, 214 IIC_DONTWAIT); 215 if (error) { 216 IIC_UNLOCK(sc); 217 return (error); 218 } 219 220 count = (int)szmin(uio->uio_resid, BUFSIZE); 221 uiomove(sc->sc_buffer, (size_t)count, uio); 222 223 error = iicbus_block_write(device_get_parent(iicdev), sc->sc_addr, 224 sc->sc_buffer, count, &sent); 225 226 iicbus_release_bus(device_get_parent(iicdev), iicdev); 227 IIC_UNLOCK(sc); 228 229 return (error); 230 } 231 232 static int 233 iicread(struct dev_read_args *ap) 234 { 235 cdev_t dev = ap->a_head.a_dev; 236 struct uio *uio = ap->a_uio; 237 struct iic_softc *sc = dev->si_drv1; 238 device_t iicdev = sc->sc_dev; 239 int len, error = 0; 240 int bufsize; 241 242 IIC_LOCK(sc); 243 if (!sc->sc_addr) { 244 IIC_UNLOCK(sc); 245 return (EINVAL); 246 } 247 248 if (sc->sc_count == 0) { 249 /* XXX: I don't think this can happen. */ 250 IIC_UNLOCK(sc); 251 return (EINVAL); 252 } 253 254 error = iicbus_request_bus(device_get_parent(iicdev), iicdev, 255 IIC_DONTWAIT); 256 if (error) { 257 IIC_UNLOCK(sc); 258 return (error); 259 } 260 261 /* max amount of data to read */ 262 len = (int)szmin(uio->uio_resid, BUFSIZE); 263 264 error = iicbus_block_read(device_get_parent(iicdev), sc->sc_addr, 265 sc->sc_inbuf, len, &bufsize); 266 if (error) { 267 IIC_UNLOCK(sc); 268 return (error); 269 } 270 271 if (bufsize > uio->uio_resid) 272 panic("%s: too much data read!", __func__); 273 274 iicbus_release_bus(device_get_parent(iicdev), iicdev); 275 276 error = uiomove(sc->sc_inbuf, (size_t)bufsize, uio); 277 IIC_UNLOCK(sc); 278 return (error); 279 } 280 281 static int 282 iicioctl(struct dev_ioctl_args *ap) 283 { 284 cdev_t dev = ap->a_head.a_dev; 285 u_long cmd = ap->a_cmd; 286 caddr_t data = ap->a_data; 287 int flags = ap->a_fflag; 288 struct iic_softc *sc = dev->si_drv1; 289 device_t iicdev = sc->sc_dev; 290 device_t parent = device_get_parent(iicdev); 291 struct iiccmd *s = (struct iiccmd *)data; 292 struct iic_rdwr_data *d = (struct iic_rdwr_data *)data; 293 struct iic_msg *m; 294 int error, count, i; 295 char *buf = NULL; 296 void **usrbufs = NULL; 297 298 if ((error = iicbus_request_bus(device_get_parent(iicdev), iicdev, 299 (flags & O_NONBLOCK) ? IIC_DONTWAIT : 300 (IIC_WAIT | IIC_INTR)))) 301 return (error); 302 303 switch (cmd) { 304 case I2CSTART: 305 IIC_LOCK(sc); 306 error = iicbus_start(parent, s->slave, 0); 307 308 /* 309 * Implicitly set the chip addr to the slave addr passed as 310 * parameter. Consequently, start/stop shall be called before 311 * the read or the write of a block. 312 */ 313 if (!error) 314 sc->sc_addr = s->slave; 315 IIC_UNLOCK(sc); 316 317 break; 318 319 case I2CSTOP: 320 error = iicbus_stop(parent); 321 break; 322 323 case I2CRSTCARD: 324 error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL); 325 break; 326 327 case I2CWRITE: 328 if (s->count <= 0) { 329 error = EINVAL; 330 break; 331 } 332 buf = kmalloc((unsigned long)s->count, M_TEMP, M_WAITOK); 333 error = copyin(s->buf, buf, s->count); 334 if (error) 335 break; 336 error = iicbus_write(parent, buf, s->count, &count, 10); 337 break; 338 339 case I2CREAD: 340 if (s->count <= 0) { 341 error = EINVAL; 342 break; 343 } 344 buf = kmalloc((unsigned long)s->count, M_TEMP, M_WAITOK); 345 error = iicbus_read(parent, buf, s->count, &count, s->last, 10); 346 if (error) 347 break; 348 error = copyout(buf, s->buf, s->count); 349 break; 350 351 case I2CRDWR: 352 buf = kmalloc(sizeof(*d->msgs) * d->nmsgs, M_TEMP, M_WAITOK); 353 usrbufs = kmalloc(sizeof(void *) * d->nmsgs, M_TEMP, M_ZERO | M_WAITOK); 354 error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs); 355 if (error) 356 break; 357 /* Alloc kernel buffers for userland data, copyin write data */ 358 for (i = 0; i < d->nmsgs; i++) { 359 m = &((struct iic_msg *)buf)[i]; 360 usrbufs[i] = m->buf; 361 m->buf = kmalloc(m->len, M_TEMP, M_WAITOK); 362 if (!(m->flags & IIC_M_RD)) 363 copyin(usrbufs[i], m->buf, m->len); 364 } 365 error = iicbus_transfer(parent, (struct iic_msg *)buf, d->nmsgs); 366 /* Copyout all read segments, free up kernel buffers */ 367 for (i = 0; i < d->nmsgs; i++) { 368 m = &((struct iic_msg *)buf)[i]; 369 if (m->flags & IIC_M_RD) 370 copyout(m->buf, usrbufs[i], m->len); 371 kfree(m->buf, M_TEMP); 372 } 373 kfree(usrbufs, M_TEMP); 374 break; 375 376 case I2CRPTSTART: 377 error = iicbus_repeated_start(parent, s->slave, 0); 378 break; 379 380 default: 381 error = ENOTTY; 382 } 383 384 iicbus_release_bus(device_get_parent(iicdev), iicdev); 385 386 if (buf != NULL) 387 kfree(buf, M_TEMP); 388 return (error); 389 } 390 391 DRIVER_MODULE(iic, iicbus, iic_driver, iic_devclass, 0, 0); 392 MODULE_DEPEND(iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 393 MODULE_VERSION(iic, 1); 394