bthub.c revision 1.1 1 /* $NetBSD: bthub.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Written by Iain Hibbert for Itronix Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: bthub.c,v 1.1 2006/06/19 15:44:45 gdamore Exp $");
36
37 #include <sys/param.h>
38 #include <sys/conf.h>
39 #include <sys/device.h>
40 #include <sys/fcntl.h>
41 #include <sys/kernel.h>
42 #include <sys/queue.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/proc.h>
46 #include <sys/systm.h>
47
48 #include <netbt/bluetooth.h>
49 #include <netbt/l2cap.h>
50
51 #include <dev/bluetooth/btdev.h>
52
53 /*****************************************************************************
54 *
55 * Bluetooth HUB pseudo-device
56 *
57 * The Bluetooth hub is a conventent place to hang devices that are
58 * actually sitting on top of the protocol stack, and not necessarily
59 * attached to any particular bluetooth interface.
60 */
61
62 struct bthub_softc {
63 struct device sc_dev;
64 LIST_HEAD(,btdev) sc_list;
65 };
66
67 /* our pseudo-device hook */
68 static struct bthub_softc *hook;
69
70 /* pseudo-device initialization */
71 void bthubattach(int);
72
73 /* autoconf(9) glue */
74 static int bthub_match(struct device *, struct cfdata *, void *);
75 static void bthub_attach(struct device *, struct device *, void *);
76 static int bthub_detach(struct device *, int);
77 static int bthub_print(void *, const char *);
78
79 CFATTACH_DECL(bthub, sizeof(struct bthub_softc),
80 bthub_match, bthub_attach, bthub_detach, NULL);
81
82 /* pseudo-device control */
83 dev_type_ioctl(bthubioctl);
84
85 const struct cdevsw bthub_cdevsw = {
86 nullopen, nullclose, noread, nowrite, bthubioctl,
87 nostop, notty, nopoll, nommap, nokqfilter,
88 };
89
90 /*****************************************************************************
91 *
92 * bthub init routine called at system boot
93 *
94 * we take this opportunity to hang a real device on our hook
95 * so that we can operate like a proper parent to our children.
96 */
97
98 extern struct cfdriver bthub_cd;
99
100 static struct cfdata bthub_cfdata = {
101 .cf_name = "bthub",
102 .cf_atname = "bthub",
103 .cf_unit = DVUNIT_ANY,
104 .cf_fstate = FSTATE_STAR,
105 };
106
107 void
108 bthubattach(int num)
109 {
110 int err;
111
112 err = config_cfattach_attach(bthub_cd.cd_name, &bthub_ca);
113 if (err) {
114 aprint_error("%s: unable to register cfattach (%d)\n",
115 bthub_cd.cd_name, err);
116
117 config_cfdriver_detach(&bthub_cd);
118 return;
119 }
120
121 hook = (struct bthub_softc *)config_attach_pseudo(&bthub_cfdata);
122 if (hook == NULL) {
123 aprint_error("%s: unable to attach bthub hook(%d)\n",
124 bthub_cd.cd_name, err);
125
126 config_cfattach_detach(bthub_cd.cd_name, &bthub_ca);
127 config_cfdriver_detach(&bthub_cd);
128 return;
129 }
130 }
131
132 /*****************************************************************************
133 *
134 * bthub autoconf(9) routines
135 *
136 * This is the real device hanging on our hook. Only the
137 * attach function will ever be called, I guess.
138 */
139
140 static int
141 bthub_match(struct device *self, struct cfdata *cfdata, void *arg)
142 {
143
144 return 1;
145 }
146
147 static void
148 bthub_attach(struct device *parent, struct device *self, void *aux)
149 {
150 struct bthub_softc *sc = (struct bthub_softc *)self;
151
152 LIST_INIT(&sc->sc_list);
153 }
154
155 static int
156 bthub_detach(struct device *self, int flags)
157 {
158 struct bthub_softc *sc = (struct bthub_softc *)self;
159 struct btdev *btdev;
160
161 while ((btdev = LIST_FIRST(&sc->sc_list)) != NULL) {
162 LIST_REMOVE(btdev, sc_next);
163 config_detach(&btdev->sc_dev, flags);
164 }
165 return 0;
166 }
167
168 /*****************************************************************************
169 *
170 * bthub control device ioctl(2)
171 *
172 * This is the method we use to control bluetooth devices,
173 * called from userland.
174 */
175
176 int
177 bthubioctl(dev_t devno, unsigned long cmd, caddr_t data, int flag, struct lwp *l)
178 {
179 struct btdev_attach_args *bda;
180 struct btdev *btdev;
181 bdaddr_t *bdaddr;
182
183 if (hook == NULL)
184 return ENXIO;
185
186 switch (cmd) {
187 case BTDEV_ATTACH: /* attach BTDEV */
188 bda = (struct btdev_attach_args *)data;
189
190 /*
191 * validate our configuration
192 */
193 if (bdaddr_any(&bda->bd_raddr)
194 || bda->bd_type == 0)
195 return EINVAL;
196
197 LIST_FOREACH(btdev, &hook->sc_list, sc_next) {
198 if (bdaddr_same(&btdev->sc_addr, &bda->bd_raddr))
199 return EADDRINUSE;
200 }
201
202 btdev = (struct btdev *)config_found((struct device *)hook,
203 bda, bthub_print);
204 if (btdev == NULL)
205 return ENXIO;
206
207 bdaddr_copy(&btdev->sc_addr, &bda->bd_raddr);
208 LIST_INSERT_HEAD(&hook->sc_list, btdev, sc_next);
209 return 0;
210
211 case BTDEV_DETACH: /* detach BTDEV */
212 bdaddr = (bdaddr_t *)data;
213
214 LIST_FOREACH(btdev, &hook->sc_list, sc_next) {
215 if (bdaddr_same(bdaddr, &btdev->sc_addr) == 0)
216 continue;
217
218 LIST_REMOVE(btdev, sc_next);
219 config_detach((struct device *)btdev, DETACH_FORCE);
220 return 0;
221 }
222 return ENXIO;
223
224 default:
225 break;
226 }
227
228 return EPASSTHROUGH;
229 }
230
231 static int
232 bthub_print(void *aux, const char *pnp)
233 {
234 struct btdev_attach_args *bda = aux;
235
236 if (pnp != NULL)
237 aprint_normal("%s: ", pnp);
238
239 aprint_verbose(" bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
240 bda->bd_raddr.b[5], bda->bd_raddr.b[4],
241 bda->bd_raddr.b[3], bda->bd_raddr.b[2],
242 bda->bd_raddr.b[1], bda->bd_raddr.b[0]);
243
244 return UNCONF;
245 }
246