2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/limits.h>
40 #include <sys/malloc.h>
41 #include <sys/ctype.h>
43 #include <sys/queue.h>
44 #include <dev/misc/gpio/gpio.h>
47 #include <sys/devfs.h>
50 LIST_ENTRY(ledsc
) list
;
57 struct gpio_mapping
*gp_map
;
60 DEVFS_DECLARE_CLONE_BITMAP(nled
);
61 static struct lock led_lock
;
62 static LIST_HEAD(, ledsc
) led_list
= LIST_HEAD_INITIALIZER(&led_list
);
63 static MALLOC_DEFINE(M_LED
, "LED", "LED driver");
67 led_open(struct dev_open_args
*ap
)
72 dev
= ap
->a_head
.a_dev
;
84 led_close(struct dev_close_args
*ap
)
89 dev
= ap
->a_head
.a_dev
;
99 led_write(struct dev_write_args
*ap
)
107 dev
= ap
->a_head
.a_dev
;
110 if (ap
->a_uio
->uio_resid
> sizeof(int))
113 len
= ap
->a_uio
->uio_resid
;
115 error
= uiomove((void *)&data
, ap
->a_uio
->uio_resid
, ap
->a_uio
);
120 data
= ((char *)&data
)[0];
125 gpio_pin_write(sc
->gp
, sc
->gp_map
, 0, data
);
131 led_read(struct dev_read_args
*ap
)
138 dev
= ap
->a_head
.a_dev
;
141 if (ap
->a_uio
->uio_resid
< sizeof(int))
144 data
= gpio_pin_read(sc
->gp
, sc
->gp_map
, 0);
146 error
= uiomove((void *)&data
,
147 (ap
->a_uio
->uio_resid
> sizeof(int))?(sizeof(int)):(ap
->a_uio
->uio_resid
),
154 led_ioctl(struct dev_ioctl_args
*ap
)
156 /* XXX: set a name */
160 static struct dev_ops nled_ops
= {
163 .d_close
= led_close
,
164 .d_write
= led_write
,
166 .d_ioctl
= led_ioctl
,
171 led_attach(struct gpio
*gp
, void *arg
, int pin
, u_int32_t mask
)
178 lockmgr(&led_lock
, LK_EXCLUSIVE
);
179 sc
= kmalloc(sizeof(struct ledsc
), M_LED
, M_WAITOK
);
181 /* XXX: check for name collisions */
182 sc
->name
= kstrdup((char *)arg
, M_LED
);
186 sc
->gp_map
= gpio_map(gp
, NULL
, pin
, 1);
187 if (sc
->gp_map
== NULL
) {
191 sc
->unit
= devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(nled
), 0);
193 LIST_INSERT_HEAD(&led_list
, sc
, list
);
194 sc
->dev
= make_dev(&nled_ops
, sc
->unit
,
195 UID_ROOT
, GID_WHEEL
, 0600, "led/%s", sc
->name
);
196 sc
->dev
->si_drv1
= sc
;
197 lockmgr(&led_lock
, LK_RELEASE
);
199 kprintf("gpio_led: Attached led '%s' to gpio %s, pin %d\n",
200 sc
->name
, sc
->gp
->driver_name
, pin
);
206 led_detach(struct gpio
*gp
, void *arg
, int pin
)
212 led_switch(const char *name
, int on_off
)
219 lockmgr(&led_lock
, LK_EXCLUSIVE
);
220 LIST_FOREACH(sc
, &led_list
, list
) {
221 if (strcmp(name
, sc
->name
) != 0)
224 gpio_pin_write(sc
->gp
, sc
->gp_map
, 0, on_off
);
228 lockmgr(&led_lock
, LK_RELEASE
);
231 struct gpio_consumer led_gpio_cons
= {
232 .consumer_name
= "led",
233 .consumer_attach
= led_attach
,
234 .consumer_detach
= led_detach
,
238 led_drvinit(void *unused
)
240 lockinit(&led_lock
, "led_lock", 0, 0);
241 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(nled
));
242 gpio_consumer_register(&led_gpio_cons
);
245 SYSINIT(leddev
, SI_SUB_DRIVERS
, SI_ORDER_MIDDLE
, led_drvinit
, NULL
);