1 /* 2 * Copyright (c) 2009 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <ahornung@gmail.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * 35 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org> 36 * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org> 37 * 38 * Permission to use, copy, modify, and distribute this software for any 39 * purpose with or without fee is hereby granted, provided that the above 40 * copyright notice and this permission notice appear in all copies. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 43 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 44 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 45 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 47 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 48 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 */ 50 /* 51 * XXX: consumer_detach stuff. 52 * XXX: userland stuff. 53 */ 54 55 #include <sys/param.h> 56 #include <sys/conf.h> 57 #include <sys/kernel.h> 58 #include <sys/systm.h> 59 #include <sys/limits.h> 60 #include <sys/thread.h> 61 #include <sys/thread2.h> 62 #include <sys/malloc.h> 63 #include <sys/ctype.h> 64 #include <sys/sbuf.h> 65 #include <sys/queue.h> 66 #include <sys/uio.h> 67 #include <sys/lock.h> 68 #include <dev/misc/gpio/gpio.h> 69 #include <sys/devfs.h> 70 71 struct gpio_driver { 72 char *name; 73 struct devfs_bitmap unit_bitmap; 74 LIST_ENTRY(gpio_driver) link; 75 }; 76 77 static LIST_HEAD(, gpio_consumer) gpio_conslist = LIST_HEAD_INITIALIZER(&gpio_conslist); 78 static LIST_HEAD(, gpio_driver) gpio_driverlist = LIST_HEAD_INITIALIZER(&gpio_driverlist); 79 DEVFS_DECLARE_CLONE_BITMAP(gpio); 80 static struct lock gpio_lock; 81 82 void 83 gpio_consumer_register(struct gpio_consumer *gcp) 84 { 85 lockmgr(&gpio_lock, LK_EXCLUSIVE); 86 LIST_INSERT_HEAD(&gpio_conslist, gcp, link); 87 lockmgr(&gpio_lock, LK_RELEASE); 88 } 89 90 void 91 gpio_consumer_unregister(struct gpio_consumer *gcp) 92 { 93 lockmgr(&gpio_lock, LK_EXCLUSIVE); 94 LIST_REMOVE(gcp, link); 95 lockmgr(&gpio_lock, LK_RELEASE); 96 } 97 98 int 99 gpio_consumer_attach(const char *consumer, void *arg, struct gpio *gp, 100 int pin, u_int32_t mask) 101 { 102 struct gpio_consumer *gcp; 103 int error = -1; 104 int locked = 0; 105 106 /* Check if it is locked already. if not, we acquire the lock */ 107 if (!(lockstatus(&gpio_lock, curthread)) == LK_EXCLUSIVE) { 108 lockmgr(&gpio_lock, LK_EXCLUSIVE); 109 locked = 1; 110 } 111 112 LIST_FOREACH(gcp, &gpio_conslist, link) { 113 if (strcmp(gcp->consumer_name, consumer) != 0) 114 continue; 115 116 if (gcp->consumer_attach) 117 error = gcp->consumer_attach(gp, arg, pin, mask); 118 if (error) { 119 kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed " 120 "(consumer error %d)\n", consumer, gp->driver_name, 121 gp->driver_unit, pin, error); 122 goto end; 123 } 124 125 kprintf("gpio: Attached consumer %s to gpio %s%d pin %d\n", 126 consumer, gp->driver_name, gp->driver_unit, pin); 127 goto end; 128 } 129 130 kprintf("gpio: Attach of consumer %s to gpio %s%d pin %d failed " 131 "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin); 132 133 end: 134 /* If we acquired the lock, we also get rid of it */ 135 if (locked) 136 lockmgr(&gpio_lock, LK_RELEASE); 137 return error; 138 } 139 140 int 141 gpio_consumer_detach(const char *consumer, struct gpio *gp, 142 int pin) 143 { 144 struct gpio_consumer *gcp; 145 int error = -1; 146 int locked = 0; 147 148 /* Check if it is locked already. if not, we acquire the lock */ 149 if (!(lockstatus(&gpio_lock, curthread)) == LK_EXCLUSIVE) { 150 lockmgr(&gpio_lock, LK_EXCLUSIVE); 151 locked = 1; 152 } 153 154 LIST_FOREACH(gcp, &gpio_conslist, link) { 155 if (strcmp(gcp->consumer_name, consumer) != 0) 156 continue; 157 158 if (gcp->consumer_detach) 159 error = gcp->consumer_detach(gp, NULL, pin); 160 if (error) { 161 kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed " 162 "(consumer error %d)\n", consumer, gp->driver_name, 163 gp->driver_unit, pin, error); 164 goto end; 165 } 166 167 kprintf("gpio: Detached consumer %s from gpio %s%d pin %d\n", 168 consumer, gp->driver_name, gp->driver_unit, pin); 169 goto end; 170 } 171 172 kprintf("gpio: Detach of consumer %s from gpio %s%d pin %d failed " 173 "(unknown consumer)\n", consumer, gp->driver_name, gp->driver_unit, pin); 174 175 end: 176 /* If we acquired the lock, we also get rid of it */ 177 if (locked) 178 lockmgr(&gpio_lock, LK_RELEASE); 179 return error; 180 } 181 182 struct gpio_mapping * 183 gpio_map(struct gpio *gp, int *map, int offset, u_int32_t mask) 184 { 185 struct gpio_mapping *gmp; 186 int npins, pin, i; 187 int locked = 0; 188 189 npins = gpio_npins(mask); 190 if (npins > gp->npins) 191 return NULL; 192 if (npins == 0) 193 return NULL; 194 195 /* Check if it is locked already. if not, we acquire the lock */ 196 if (!(lockstatus(&gpio_lock, curthread)) == LK_EXCLUSIVE) { 197 lockmgr(&gpio_lock, LK_EXCLUSIVE); 198 locked = 1; 199 } 200 201 gmp = kmalloc(sizeof(struct gpio_mapping), M_TEMP, M_WAITOK); 202 gmp->gp = gp; 203 if (map) { 204 gmp->map = map; 205 gmp->map_alloced = 0; 206 } else { 207 gmp->map = kmalloc(sizeof(int) * npins, M_TEMP, M_WAITOK); 208 gmp->map_alloced = 1; 209 } 210 211 for (npins = 0, i = 0; i < 32; i++) 212 if (mask & (1 << i)) { 213 pin = offset + i; 214 if (pin < 0 || pin >= gp->npins || 215 gp->pins[pin].pin_mapped || gp->pins[pin].pin_opened) { 216 if (map == NULL) 217 kfree(gmp->map, M_TEMP); 218 kfree(gmp, M_TEMP); 219 /* If we acquired the lock, we also get rid of it */ 220 if (locked) 221 lockmgr(&gpio_lock, LK_RELEASE); 222 return NULL; 223 } 224 gp->pins[pin].pin_mapped = 1; 225 gmp->map[npins++] = pin; 226 } 227 gmp->size = npins; 228 229 /* If we acquired the lock, we also get rid of it */ 230 if (locked) 231 lockmgr(&gpio_lock, LK_RELEASE); 232 233 return gmp; 234 } 235 236 void 237 gpio_unmap(struct gpio_mapping *gmp) 238 { 239 int pin, i; 240 int locked = 0; 241 242 /* Check if it is locked already. if not, we acquire the lock */ 243 if (!(lockstatus(&gpio_lock, curthread)) == LK_EXCLUSIVE) { 244 lockmgr(&gpio_lock, LK_EXCLUSIVE); 245 locked = 1; 246 } 247 248 for (i = 0; i < gmp->size; i++) { 249 pin = gmp->map[i]; 250 gmp->gp->pins[pin].pin_mapped = 0; 251 } 252 253 if (gmp->map_alloced) 254 kfree(gmp->map, M_TEMP); 255 kfree(gmp, M_TEMP); 256 257 /* If we acquired the lock, we also get rid of it */ 258 if (locked) 259 lockmgr(&gpio_lock, LK_RELEASE); 260 } 261 262 int 263 gpio_npins(u_int32_t mask) 264 { 265 int npins, i; 266 267 for (npins = 0, i = 0; i < 32; i++) 268 if (mask & (1 << i)) 269 npins++; 270 271 return (npins); 272 } 273 274 int 275 gpio_pin_read(struct gpio *gp, struct gpio_mapping *map, int pin) 276 { 277 return gp->pin_read(gp->arg, map->map[pin]); 278 } 279 280 void 281 gpio_pin_write(struct gpio *gp, struct gpio_mapping *map, int pin, int data) 282 { 283 return gp->pin_write(gp->arg, map->map[pin], data); 284 } 285 286 void 287 gpio_pin_ctl(struct gpio *gp, struct gpio_mapping *map, int pin, int flags) 288 { 289 return gp->pin_ctl(gp->arg, map->map[pin], flags); 290 } 291 292 int 293 gpio_pin_caps(struct gpio *gp, struct gpio_mapping *map, int pin) 294 { 295 return (gp->pins[map->map[pin]].pin_caps); 296 } 297 298 static int 299 gpio_open(struct dev_open_args *ap) 300 { 301 struct gpio *gp; 302 gpio_pin_t *pin; 303 cdev_t dev; 304 305 dev = ap->a_head.a_dev; 306 gp = dev->si_drv1; 307 pin = dev->si_drv2; 308 309 if (pin->pin_opened || pin->pin_mapped) 310 return EBUSY; 311 312 pin->pin_opened = 1; 313 314 return 0; 315 } 316 317 static int 318 gpio_close(struct dev_close_args *ap) 319 { 320 struct gpio *gp; 321 gpio_pin_t *pin; 322 cdev_t dev; 323 324 dev = ap->a_head.a_dev; 325 gp = dev->si_drv1; 326 pin = dev->si_drv2; 327 328 if (pin->pin_opened) 329 pin->pin_opened = 0; 330 331 return 0; 332 } 333 334 static int 335 gpio_write(struct dev_write_args *ap) 336 { 337 struct gpio *gp; 338 gpio_pin_t *pin; 339 cdev_t dev; 340 int error; 341 int data = 0; 342 343 dev = ap->a_head.a_dev; 344 gp = dev->si_drv1; 345 pin = dev->si_drv2; 346 347 if (ap->a_uio->uio_resid > sizeof(int)) 348 return EINVAL; 349 350 error = uiomove((void *)&data, ap->a_uio->uio_resid, ap->a_uio); 351 if (error) 352 return error; 353 354 if (data != GPIO_PIN_LOW && data != GPIO_PIN_HIGH) 355 return EINVAL; 356 357 gp->pin_write(gp->arg, pin->pin_num, data); 358 pin->pin_state = data; 359 360 return 0; 361 } 362 363 static int 364 gpio_read(struct dev_read_args *ap) 365 { 366 struct gpio *gp; 367 gpio_pin_t *pin; 368 cdev_t dev; 369 int error; 370 int data = 0; 371 372 dev = ap->a_head.a_dev; 373 gp = dev->si_drv1; 374 pin = dev->si_drv2; 375 376 if (ap->a_uio->uio_resid < sizeof(char)) 377 return EINVAL; 378 379 data = gp->pin_read(gp->arg, pin->pin_num); 380 381 error = uiomove((void *)&data, 382 (ap->a_uio->uio_resid > sizeof(int))?(sizeof(int)):(ap->a_uio->uio_resid), 383 ap->a_uio); 384 385 return error; 386 } 387 388 static int 389 gpio_ioctl(struct dev_ioctl_args *ap) 390 { 391 struct gpio_pin_set_args *gpsa; 392 struct gpio *gp; 393 gpio_pin_t *pin; 394 cdev_t dev; 395 int error = 0; 396 397 dev = ap->a_head.a_dev; 398 gp = dev->si_drv1; 399 pin = dev->si_drv2; 400 401 switch(ap->a_cmd) { 402 case GPIOPINSET: 403 gpsa = (struct gpio_pin_set_args *)ap->a_data; 404 if (pin->pin_opened || pin->pin_mapped) 405 return EBUSY; 406 407 gpsa->caps = pin->pin_caps; 408 gpsa->flags = pin->pin_flags; 409 410 if ((gpsa->flags & pin->pin_caps) != gpsa->flags) 411 return ENODEV; 412 413 if (gpsa->flags > 0) { 414 gp->pin_ctl(gp->arg, pin->pin_num, gpsa->flags); 415 pin->pin_flags = gpsa->flags | GPIO_PIN_SET; 416 } 417 break; 418 419 case GPIOPINUNSET: 420 gpsa = (struct gpio_pin_set_args *)ap->a_data; 421 error = EINVAL; 422 break; 423 424 default: 425 return EINVAL; 426 } 427 return 0; 428 } 429 430 static int 431 gpio_master_ioctl(struct dev_ioctl_args *ap) 432 { 433 struct gpio_pin_set_args *gpsa; 434 struct gpio_info *gpi; 435 struct gpio_attach_args *gpaa; 436 struct gpio *gp; 437 cdev_t dev; 438 gpio_pin_t *pin; 439 int error = 0; 440 441 dev = ap->a_head.a_dev; 442 gp = dev->si_drv1; 443 444 switch(ap->a_cmd) { 445 case GPIOINFO: 446 gpi = (struct gpio_info *)ap->a_data; 447 gpi->npins = gp->npins; 448 if (gpi->pins != NULL) { 449 error = copyout(gp->pins, gpi->pins, 450 sizeof(struct gpio_pin)*gp->npins); 451 } 452 break; 453 454 case GPIOATTACH: 455 gpaa = (struct gpio_attach_args *)ap->a_data; 456 error = gpio_consumer_attach(gpaa->consumer_name, 457 (gpaa->arg_type == GPIO_TYPE_INT)? 458 ((void *)gpaa->consumer_arg.lint): 459 (gpaa->consumer_arg.string), 460 gp, gpaa->pin_offset, gpaa->pin_mask); 461 break; 462 463 case GPIODETACH: 464 gpaa = (struct gpio_attach_args *)ap->a_data; 465 error = gpio_consumer_detach(gpaa->consumer_name, gp, 466 gpaa->pin_offset); 467 break; 468 469 case GPIOPINSET: 470 gpsa = (struct gpio_pin_set_args *)ap->a_data; 471 if (gpsa->pin < 0 || gpsa->pin >= gp->npins) 472 return EINVAL; 473 474 pin = &gp->pins[gpsa->pin]; 475 476 if (pin->pin_opened || pin->pin_mapped) 477 return EBUSY; 478 479 gpsa->caps = pin->pin_caps; 480 gpsa->flags = pin->pin_flags; 481 482 if ((gpsa->flags & pin->pin_caps) != gpsa->flags) 483 return ENODEV; 484 485 if (gpsa->flags > 0) { 486 gp->pin_ctl(gp->arg, gpsa->pin, gpsa->flags); 487 pin->pin_flags = gpsa->flags | GPIO_PIN_SET; 488 } 489 break; 490 491 case GPIOPINUNSET: 492 gpsa = (struct gpio_pin_set_args *)ap->a_data; 493 error = EINVAL; 494 break; 495 496 default: 497 return EINVAL; 498 } 499 500 return error; 501 } 502 503 static struct dev_ops gpio_ops = { 504 { "gpio", 0, 0 }, 505 .d_open = gpio_open, 506 .d_close = gpio_close, 507 .d_write = gpio_write, 508 .d_read = gpio_read, 509 .d_ioctl = gpio_ioctl, 510 }; 511 512 static struct dev_ops gpio_master_ops = { 513 { "gpio", 0, 0 }, 514 .d_ioctl = gpio_master_ioctl, 515 }; 516 517 void 518 gpio_register(struct gpio *gp) 519 { 520 struct gpio_driver *gpd; 521 int i, unit, master_unit = -1; 522 523 KKASSERT(gp->npins > 0); 524 KKASSERT(gp->pins); 525 526 lockmgr(&gpio_lock, LK_EXCLUSIVE); 527 LIST_FOREACH(gpd, &gpio_driverlist, link) { 528 if (strcmp(gpd->name, gp->driver_name) != 0) 529 continue; 530 531 master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0); 532 break; 533 } 534 if (master_unit == -1) { 535 gpd = kmalloc(sizeof(struct gpio_driver), 536 M_TEMP, M_WAITOK | M_ZERO); 537 gpd->name = kstrdup(gp->driver_name, M_TEMP); 538 devfs_clone_bitmap_init(&gpd->unit_bitmap); 539 master_unit = devfs_clone_bitmap_get(&gpd->unit_bitmap, 0); 540 LIST_INSERT_HEAD(&gpio_driverlist, gpd, link); 541 } 542 lockmgr(&gpio_lock, LK_RELEASE); 543 544 gp->driver_unit = master_unit; 545 kprintf("gpio: GPIO driver %s%d registered, npins = %d\n", 546 gp->driver_name, master_unit, gp->npins); 547 548 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0); 549 gp->master_dev = make_dev(&gpio_master_ops, unit, UID_ROOT, GID_WHEEL, 0600, 550 "gpio/%s%d/master", gp->driver_name, master_unit); 551 gp->master_dev->si_drv1 = gp; 552 553 for (i = 0; i < gp->npins; i++) { 554 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 0); 555 gp->pins[i].dev = make_dev(&gpio_ops, unit, UID_ROOT, GID_WHEEL, 0600, 556 "gpio/%s%d/%d", gp->driver_name, master_unit, gp->pins[i].pin_num); 557 gp->pins[i].dev->si_drv1 = gp; 558 gp->pins[i].dev->si_drv2 = &gp->pins[i]; 559 } 560 } 561 562 void 563 gpio_unregister(struct gpio *gp) 564 { 565 struct gpio_driver *gpd; 566 int i; 567 568 KKASSERT(gp->npins > 0); 569 KKASSERT(gp->pins); 570 571 for (i = 0; i < gp->npins; i++) { 572 devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(gpio), 573 minor(gp->pins[i].dev)); 574 destroy_dev(gp->pins[i].dev); 575 } 576 577 destroy_dev(gp->master_dev); 578 579 lockmgr(&gpio_lock, LK_EXCLUSIVE); 580 LIST_FOREACH(gpd, &gpio_driverlist, link) { 581 if (strcmp(gpd->name, gp->driver_name) != 0) 582 continue; 583 584 devfs_clone_bitmap_put(&gpd->unit_bitmap, gp->driver_unit); 585 LIST_REMOVE(gpd, link); 586 break; 587 } 588 lockmgr(&gpio_lock, LK_RELEASE); 589 590 kprintf("gpio: GPIO driver %s%d unregistered\n", 591 gp->driver_name, gp->driver_unit); 592 } 593 594 static void 595 gpio_drvinit(void *unused) 596 { 597 lockinit(&gpio_lock, "gpio_lock", 0, 0); 598 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(gpio)); 599 } 600 601 SYSINIT(gpio, SI_SUB_PRE_DRIVERS, SI_ORDER_FIRST, gpio_drvinit, NULL); 602