File: | src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.cpp |
Warning: | line 153, column 2 Use of memory after it is freed |
1 | /* | |||
2 | * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com | |||
3 | * Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com | |||
4 | * All rights reserved. Distributed under the terms of the MIT License. | |||
5 | * | |||
6 | */ | |||
7 | ||||
8 | ||||
9 | #include "h2generic.h" | |||
10 | ||||
11 | #include <kernel.h> | |||
12 | #include <malloc.h> | |||
13 | #include <stdio.h> | |||
14 | #include <string.h> | |||
15 | ||||
16 | #include <KernelExport.h> | |||
17 | #include <ByteOrder.h> | |||
18 | #include <Drivers.h> | |||
19 | ||||
20 | #include <btModules.h> | |||
21 | ||||
22 | #include "snet_buffer.h" | |||
23 | #include "h2cfg.h" | |||
24 | #include "h2debug.h" | |||
25 | #include "h2transactions.h" | |||
26 | #include "h2util.h" | |||
27 | ||||
28 | ||||
29 | int32 api_version = B_CUR_DRIVER_API_VERSION2; | |||
30 | ||||
31 | // Modules | |||
32 | static const char* usb_name = B_USB_MODULE_NAME"bus_managers/usb/v3"; | |||
33 | static const char* hci_name = BT_HCI_MODULE_NAME"bluetooth/hci/v1"; | |||
34 | static const char* btDevices_name = BT_HCI_MODULE_NAME"bluetooth/hci/v1"; | |||
35 | ||||
36 | ||||
37 | usb_module_info* usb = NULL__null; | |||
38 | bt_hci_module_info* hci = NULL__null; // TODO remove / clean | |||
39 | struct bt_hci_module_info* btDevices = NULL__null; | |||
40 | struct net_buffer_module_info* nb = NULL__null; | |||
41 | struct bluetooth_core_data_module_info* btCoreData = NULL__null; | |||
42 | ||||
43 | // Driver Global data | |||
44 | static char* publish_names[MAX_BT_GENERIC_USB_DEVICES16]; | |||
45 | ||||
46 | int32 dev_count = 0; // number of connected devices | |||
47 | static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES16]; | |||
48 | sem_id dev_table_sem = -1; // sem to synchronize access to device table | |||
49 | ||||
50 | status_t submit_nbuffer(hci_id hid, net_buffer* nbuf); | |||
51 | ||||
52 | usb_support_descriptor supported_devices[] = { | |||
53 | // Generic Bluetooth USB device | |||
54 | // Class, SubClass, and Protocol codes that describe a Bluetooth device | |||
55 | { UDCLASS_WIRELESS0xe0, UDSUBCLASS_RF0x01, UDPROTO_BLUETOOTH0x01 , 0 , 0 }, | |||
56 | ||||
57 | // Broadcom BCM2035 | |||
58 | { 0, 0, 0, 0x0a5c, 0x200a }, | |||
59 | { 0, 0, 0, 0x0a5c, 0x2009 }, | |||
60 | ||||
61 | // Devices taken from the linux Driver | |||
62 | // AVM BlueFRITZ! USB v2.0 | |||
63 | { 0, 0, 0, 0x057c, 0x3800 }, | |||
64 | // Bluetooth Ultraport Module from IBM | |||
65 | { 0, 0, 0, 0x04bf, 0x030a }, | |||
66 | // ALPS Modules with non-standard id | |||
67 | { 0, 0, 0, 0x044e, 0x3001 }, | |||
68 | { 0, 0, 0, 0x044e, 0x3002 }, | |||
69 | // Ericsson with non-standard id | |||
70 | { 0, 0, 0, 0x0bdb, 0x1002 } | |||
71 | }; | |||
72 | ||||
73 | /* add a device to the list of connected devices */ | |||
74 | #ifdef HAIKU_TARGET_PLATFORM_HAIKU1 | |||
75 | static bt_usb_dev* | |||
76 | spawn_device(usb_device usb_dev) | |||
77 | #else | |||
78 | static bt_usb_dev* | |||
79 | spawn_device(usb_device* usb_dev) | |||
80 | #endif | |||
81 | ||||
82 | { | |||
83 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
84 | ||||
85 | int32 i; | |||
86 | status_t err = B_OK((int)0); | |||
87 | bt_usb_dev* new_bt_dev = NULL__null; | |||
88 | ||||
89 | // 16 usb dongles... | |||
90 | if (dev_count >= MAX_BT_GENERIC_USB_DEVICES16) { | |||
91 | ERROR("%s: Device table full\n", __func__)dprintf("h2generic: " "%s: Device table full\n", __func__); | |||
92 | goto exit; | |||
93 | } | |||
94 | ||||
95 | // try the allocation | |||
96 | new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev)); | |||
97 | if (new_bt_dev == NULL__null) { | |||
98 | ERROR("%s: Unable to malloc new bt device\n", __func__)dprintf("h2generic: " "%s: Unable to malloc new bt device\n", __func__); | |||
99 | goto exit; | |||
100 | } | |||
101 | memset(new_bt_dev, 0, sizeof(bt_usb_dev)); | |||
102 | ||||
103 | // We will need this sem for some flow control | |||
104 | new_bt_dev->cmd_complete = create_sem(1, | |||
105 | BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic" "cmd_complete"); | |||
106 | if (new_bt_dev->cmd_complete < 0) { | |||
107 | err = new_bt_dev->cmd_complete; | |||
108 | goto bail0; | |||
109 | } | |||
110 | ||||
111 | // and this for something else | |||
112 | new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic" "lock"); | |||
113 | if (new_bt_dev->lock < 0) { | |||
114 | err = new_bt_dev->lock; | |||
115 | goto bail1; | |||
116 | } | |||
117 | ||||
118 | // find a free slot and fill out the name | |||
119 | acquire_sem(dev_table_sem); | |||
120 | for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES16; i++) { | |||
121 | if (bt_usb_devices[i] == NULL__null) { | |||
122 | bt_usb_devices[i] = new_bt_dev; | |||
123 | sprintf(new_bt_dev->name, "%s/%" B_PRId32"" "d", | |||
124 | BLUETOOTH_DEVICE_PATH"bluetooth/" "h2" "/" "h2" "generic", i); | |||
125 | new_bt_dev->num = i; | |||
126 | TRACE("%s: added device %p %" B_PRId32 " %s\n", __func__,dprintf("h2generic: " "%s: added device %p %" "" "d" " %s\n", __func__, bt_usb_devices[i], new_bt_dev->num, new_bt_dev-> name) | |||
127 | bt_usb_devices[i], new_bt_dev->num, new_bt_dev->name)dprintf("h2generic: " "%s: added device %p %" "" "d" " %s\n", __func__, bt_usb_devices[i], new_bt_dev->num, new_bt_dev-> name); | |||
128 | break; | |||
129 | } | |||
130 | } | |||
131 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
132 | ||||
133 | // In the case we cannot us | |||
134 | if (bt_usb_devices[i] != new_bt_dev) { | |||
135 | ERROR("%s: Device could not be added\n", __func__)dprintf("h2generic: " "%s: Device could not be added\n", __func__ ); | |||
136 | goto bail2; | |||
137 | } | |||
138 | ||||
139 | new_bt_dev->dev = usb_dev; | |||
140 | // TODO: currently only server opens | |||
141 | new_bt_dev->open_count = 0; | |||
142 | ||||
143 | dev_count++; | |||
144 | return new_bt_dev; | |||
145 | ||||
146 | bail2: | |||
147 | delete_sem(new_bt_dev->lock); | |||
148 | bail1: | |||
149 | delete_sem(new_bt_dev->cmd_complete); | |||
150 | bail0: | |||
151 | free(new_bt_dev); | |||
152 | exit: | |||
153 | return new_bt_dev; | |||
| ||||
154 | } | |||
155 | ||||
156 | ||||
157 | // remove a device from the list of connected devices | |||
158 | static void | |||
159 | kill_device(bt_usb_dev* bdev) | |||
160 | { | |||
161 | if (bdev != NULL__null) { | |||
162 | TRACE("%s: (%p)\n", __func__, bdev)dprintf("h2generic: " "%s: (%p)\n", __func__, bdev); | |||
163 | ||||
164 | delete_sem(bdev->lock); | |||
165 | delete_sem(bdev->cmd_complete); | |||
166 | ||||
167 | // mark it free | |||
168 | bt_usb_devices[bdev->num] = NULL__null; | |||
169 | ||||
170 | free(bdev); | |||
171 | dev_count--; | |||
172 | } | |||
173 | } | |||
174 | ||||
175 | ||||
176 | bt_usb_dev* | |||
177 | fetch_device(bt_usb_dev* dev, hci_id hid) | |||
178 | { | |||
179 | int i; | |||
180 | ||||
181 | // TRACE("%s: (%p) or %d\n", __func__, dev, hid); | |||
182 | ||||
183 | acquire_sem(dev_table_sem); | |||
184 | if (dev != NULL__null) { | |||
185 | for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES16; i++) { | |||
186 | if (bt_usb_devices[i] == dev) { | |||
187 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
188 | return bt_usb_devices[i]; | |||
189 | } | |||
190 | } | |||
191 | } else { | |||
192 | for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES16; i++) { | |||
193 | if (bt_usb_devices[i] != NULL__null && bt_usb_devices[i]->hdev == hid) { | |||
194 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
195 | return bt_usb_devices[i]; | |||
196 | } | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
201 | ||||
202 | return NULL__null; | |||
203 | } | |||
204 | ||||
205 | ||||
206 | #if 0 | |||
207 | #pragma mark - | |||
208 | #endif | |||
209 | ||||
210 | // called by USB Manager when device is added to the USB | |||
211 | #ifdef HAIKU_TARGET_PLATFORM_HAIKU1 | |||
212 | static status_t | |||
213 | device_added(usb_device dev, void** cookie) | |||
214 | #else | |||
215 | device_added(usb_device* dev, void** cookie) | |||
216 | #endif | |||
217 | { | |||
218 | const usb_interface_info* interface; | |||
219 | const usb_device_descriptor* desc; | |||
220 | const usb_configuration_info* config; | |||
221 | const usb_interface_info* uif; | |||
222 | const usb_endpoint_info* ep; | |||
223 | ||||
224 | status_t err = B_ERROR(-1); | |||
225 | bt_usb_dev* new_bt_dev = spawn_device(dev); | |||
| ||||
226 | int e; | |||
227 | ||||
228 | TRACE("%s: device_added(%p)\n", __func__, new_bt_dev)dprintf("h2generic: " "%s: device_added(%p)\n", __func__, new_bt_dev ); | |||
229 | ||||
230 | if (new_bt_dev == NULL__null) { | |||
231 | ERROR("%s: Couldn't allocate device record.\n", __func__)dprintf("h2generic: " "%s: Couldn't allocate device record.\n" , __func__); | |||
232 | err = ENOMEM((-2147483647 - 1) + 0); | |||
233 | goto bail_no_mem; | |||
234 | } | |||
235 | ||||
236 | // we only have 1 configuration number 0 | |||
237 | config = usb->get_nth_configuration(dev, 0); | |||
238 | // dump_usb_configuration_info(config); | |||
239 | if (config == NULL__null) { | |||
240 | ERROR("%s: Couldn't get default USB config.\n", __func__)dprintf("h2generic: " "%s: Couldn't get default USB config.\n" , __func__); | |||
241 | err = B_ERROR(-1); | |||
242 | goto bail; | |||
243 | } | |||
244 | ||||
245 | TRACE("%s: found %" B_PRIuSIZE " alt interfaces.\n", __func__,dprintf("h2generic: " "%s: found %" "l" "u" " alt interfaces.\n" , __func__, config->interface->alt_count) | |||
246 | config->interface->alt_count)dprintf("h2generic: " "%s: found %" "l" "u" " alt interfaces.\n" , __func__, config->interface->alt_count); | |||
247 | ||||
248 | // set first interface | |||
249 | interface = &config->interface->alt[0]; | |||
250 | err = usb->set_alt_interface(new_bt_dev->dev, interface); | |||
251 | ||||
252 | if (err != B_OK((int)0)) { | |||
253 | ERROR("%s: set_alt_interface() error.\n", __func__)dprintf("h2generic: " "%s: set_alt_interface() error.\n", __func__ ); | |||
254 | goto bail; | |||
255 | } | |||
256 | ||||
257 | // call set_configuration() only after calling set_alt_interface() | |||
258 | err = usb->set_configuration(dev, config); | |||
259 | if (err != B_OK((int)0)) { | |||
260 | ERROR("%s: set_configuration() error.\n", __func__)dprintf("h2generic: " "%s: set_configuration() error.\n", __func__ ); | |||
261 | goto bail; | |||
262 | } | |||
263 | ||||
264 | // Place to find out whats our concrete device and set up some special | |||
265 | // info to our driver. If this code increases too much reconsider | |||
266 | // this implementation | |||
267 | desc = usb->get_device_descriptor(dev); | |||
268 | if (desc->vendor_id == 0x0a5c | |||
269 | && (desc->product_id == 0x200a | |||
270 | || desc->product_id == 0x2009 | |||
271 | || desc->product_id == 0x2035)) { | |||
272 | ||||
273 | new_bt_dev->driver_info = BT_WILL_NEED_A_RESET(1 << 2) | BT_SCO_NOT_WORKING(1 << 1); | |||
274 | ||||
275 | } | |||
276 | /* | |||
277 | else if ( desc->vendor_id == YOUR_VENDOR_HERE | |||
278 | && desc->product_id == YOUR_PRODUCT_HERE ) { | |||
279 | YOUR_SPECIAL_FLAGS_HERE | |||
280 | } | |||
281 | */ | |||
282 | ||||
283 | if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE(1 << 0)) { | |||
284 | err = ENODEV(((-2147483647 - 1) + 0x7000) + 7); | |||
285 | goto bail; | |||
286 | } | |||
287 | ||||
288 | // security check | |||
289 | if (config->interface->active->descr->interface_number > 0) { | |||
290 | ERROR("%s: Strange condition happened %d\n", __func__,dprintf("h2generic: " "%s: Strange condition happened %d\n", __func__ , config->interface->active->descr->interface_number ) | |||
291 | config->interface->active->descr->interface_number)dprintf("h2generic: " "%s: Strange condition happened %d\n", __func__ , config->interface->active->descr->interface_number ); | |||
292 | err = B_ERROR(-1); | |||
293 | goto bail; | |||
294 | } | |||
295 | ||||
296 | TRACE("%s: Found %" B_PRIuSIZE " interfaces. Expected 3\n", __func__,dprintf("h2generic: " "%s: Found %" "l" "u" " interfaces. Expected 3\n" , __func__, config->interface_count) | |||
297 | config->interface_count)dprintf("h2generic: " "%s: Found %" "l" "u" " interfaces. Expected 3\n" , __func__, config->interface_count); | |||
298 | ||||
299 | // Find endpoints that we need | |||
300 | uif = config->interface->active; | |||
301 | for (e = 0; e < uif->descr->num_endpoints; e++) { | |||
302 | ||||
303 | ep = &uif->endpoint[e]; | |||
304 | switch (ep->descr->attributes & USB_ENDPOINT_ATTR_MASK0x03) { | |||
305 | case USB_ENDPOINT_ATTR_INTERRUPT0x03: | |||
306 | if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN0x80) | |||
307 | { | |||
308 | new_bt_dev->intr_in_ep = ep; | |||
309 | new_bt_dev->max_packet_size_intr_in | |||
310 | = ep->descr->max_packet_size; | |||
311 | TRACE("%s: INT in\n", __func__)dprintf("h2generic: " "%s: INT in\n", __func__); | |||
312 | } else { | |||
313 | TRACE("%s: INT out\n", __func__)dprintf("h2generic: " "%s: INT out\n", __func__); | |||
314 | } | |||
315 | break; | |||
316 | ||||
317 | case USB_ENDPOINT_ATTR_BULK0x02: | |||
318 | if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN0x80) { | |||
319 | new_bt_dev->bulk_in_ep = ep; | |||
320 | new_bt_dev->max_packet_size_bulk_in | |||
321 | = ep->descr->max_packet_size; | |||
322 | TRACE("%s: BULK int\n", __func__)dprintf("h2generic: " "%s: BULK int\n", __func__); | |||
323 | } else { | |||
324 | new_bt_dev->bulk_out_ep = ep; | |||
325 | new_bt_dev->max_packet_size_bulk_out | |||
326 | = ep->descr->max_packet_size; | |||
327 | TRACE("%s: BULK out\n", __func__)dprintf("h2generic: " "%s: BULK out\n", __func__); | |||
328 | } | |||
329 | break; | |||
330 | } | |||
331 | } | |||
332 | ||||
333 | if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep | |||
334 | || !new_bt_dev->intr_in_ep) { | |||
335 | ERROR("%s: Minimal # endpoints for BT not found\n", __func__)dprintf("h2generic: " "%s: Minimal # endpoints for BT not found\n" , __func__); | |||
336 | goto bail; | |||
337 | } | |||
338 | ||||
339 | // Look into the devices suported to understand this | |||
340 | if (new_bt_dev->driver_info & BT_DIGIANSWER(1 << 4)) | |||
341 | new_bt_dev->ctrl_req = USB_TYPE_VENDOR(0x02 << 5); | |||
342 | else | |||
343 | new_bt_dev->ctrl_req = USB_TYPE_CLASS(0x01 << 5); | |||
344 | ||||
345 | new_bt_dev->connected = true; | |||
346 | ||||
347 | // set the cookie that will be passed to other USB | |||
348 | // hook functions (currently device_removed() is the only other) | |||
349 | *cookie = new_bt_dev; | |||
350 | TRACE("%s: Ok %p\n", __func__, new_bt_dev)dprintf("h2generic: " "%s: Ok %p\n", __func__, new_bt_dev); | |||
351 | return B_OK((int)0); | |||
352 | ||||
353 | bail: | |||
354 | kill_device(new_bt_dev); | |||
355 | bail_no_mem: | |||
356 | *cookie = NULL__null; | |||
357 | ||||
358 | return err; | |||
359 | } | |||
360 | ||||
361 | ||||
362 | // Called by USB Manager when device is removed from the USB | |||
363 | static status_t | |||
364 | device_removed(void* cookie) | |||
365 | { | |||
366 | bt_usb_dev* bdev = fetch_device((bt_usb_dev*)cookie, 0); | |||
367 | ||||
368 | TRACE("%s: device_removed(%p)\n", __func__, bdev)dprintf("h2generic: " "%s: device_removed(%p)\n", __func__, bdev ); | |||
369 | ||||
370 | if (bdev == NULL__null) { | |||
371 | ERROR("%s: Device not present in driver.\n", __func__)dprintf("h2generic: " "%s: Device not present in driver.\n", __func__ ); | |||
372 | return B_ERROR(-1); | |||
373 | } | |||
374 | ||||
375 | if (!TEST_AND_CLEAR(&bdev->state, RUNNING)) | |||
376 | ERROR("%s: wasnt running?\n", __func__)dprintf("h2generic: " "%s: wasnt running?\n", __func__); | |||
377 | ||||
378 | TRACE("%s: Cancelling queues...\n", __func__)dprintf("h2generic: " "%s: Cancelling queues...\n", __func__); | |||
379 | if (bdev->intr_in_ep != NULL__null) | |||
380 | usb->cancel_queued_transfers(bdev->intr_in_ep->handle); | |||
381 | if (bdev->bulk_in_ep != NULL__null) | |||
382 | usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); | |||
383 | if (bdev->bulk_out_ep != NULL__null) | |||
384 | usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); | |||
385 | ||||
386 | bdev->connected = false; | |||
387 | ||||
388 | return B_OK((int)0); | |||
389 | } | |||
390 | ||||
391 | ||||
392 | static bt_hci_transport_hooks bluetooth_hooks = { | |||
393 | NULL__null, | |||
394 | &submit_nbuffer, | |||
395 | &submit_nbuffer, | |||
396 | NULL__null, | |||
397 | NULL__null, | |||
398 | H2 | |||
399 | }; | |||
400 | ||||
401 | ||||
402 | static usb_notify_hooks notify_hooks = { | |||
403 | &device_added, | |||
404 | &device_removed | |||
405 | }; | |||
406 | ||||
407 | #if 0 | |||
408 | #pragma mark - | |||
409 | #endif | |||
410 | ||||
411 | status_t | |||
412 | submit_nbuffer(hci_id hid, net_buffer* nbuf) | |||
413 | { | |||
414 | bt_usb_dev* bdev = NULL__null; | |||
415 | ||||
416 | bdev = fetch_device(NULL__null, hid); | |||
417 | ||||
418 | TRACE("%s: index=%" B_PRId32 " nbuf=%p bdev=%p\n", __func__, hid,dprintf("h2generic: " "%s: index=%" "" "d" " nbuf=%p bdev=%p\n" , __func__, hid, nbuf, bdev) | |||
419 | nbuf, bdev)dprintf("h2generic: " "%s: index=%" "" "d" " nbuf=%p bdev=%p\n" , __func__, hid, nbuf, bdev); | |||
420 | ||||
421 | if (bdev != NULL__null) { | |||
422 | switch (nbuf->protocol) { | |||
423 | case BT_COMMAND: | |||
424 | // not issued this way | |||
425 | break; | |||
426 | ||||
427 | case BT_ACL: | |||
428 | return submit_tx_acl(bdev, nbuf); | |||
429 | break; | |||
430 | ||||
431 | default: | |||
432 | panic("submit_nbuffer: no protocol"); | |||
433 | break; | |||
434 | ||||
435 | } | |||
436 | } | |||
437 | ||||
438 | return B_ERROR(-1); | |||
439 | ||||
440 | } | |||
441 | ||||
442 | ||||
443 | // implements the POSIX open() | |||
444 | static status_t | |||
445 | device_open(const char* name, uint32 flags, void **cookie) | |||
446 | { | |||
447 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
448 | ||||
449 | status_t err = ENODEV(((-2147483647 - 1) + 0x7000) + 7); | |||
450 | bt_usb_dev* bdev = NULL__null; | |||
451 | hci_id hdev; | |||
452 | int i; | |||
453 | ||||
454 | acquire_sem(dev_table_sem); | |||
455 | for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES16; i++) { | |||
456 | if (bt_usb_devices[i] && !strcmp(name, bt_usb_devices[i]->name)) { | |||
457 | bdev = bt_usb_devices[i]; | |||
458 | break; | |||
459 | } | |||
460 | } | |||
461 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
462 | ||||
463 | if (bdev == NULL__null) { | |||
464 | ERROR("%s: Device not found in the open list!", __func__)dprintf("h2generic: " "%s: Device not found in the open list!" , __func__); | |||
465 | *cookie = NULL__null; | |||
466 | return B_ERROR(-1); | |||
467 | } | |||
468 | ||||
469 | // Set RUNNING | |||
470 | if (TEST_AND_SET(&bdev->state, RUNNING)) { | |||
471 | ERROR("%s: dev already running! - reOpened device!\n", __func__)dprintf("h2generic: " "%s: dev already running! - reOpened device!\n" , __func__); | |||
472 | return B_ERROR(-1); | |||
473 | } | |||
474 | ||||
475 | acquire_sem(bdev->lock); | |||
476 | // TX structures | |||
477 | for (i = 0; i < BT_DRIVER_TXCOVERAGE(1 + 1 + 0 + 0); i++) { | |||
478 | list_init(&bdev->nbuffersTx[i]); | |||
479 | bdev->nbuffersPendingTx[i] = 0; | |||
480 | } | |||
481 | ||||
482 | // RX structures | |||
483 | bdev->eventRx = NULL__null; | |||
484 | for (i = 0; i < BT_DRIVER_RXCOVERAGE(1 + 1 + 0 + 0); i++) { | |||
485 | bdev->nbufferRx[i] = NULL__null; | |||
486 | } | |||
487 | ||||
488 | // dumping the USB frames | |||
489 | init_room(&bdev->eventRoom); | |||
490 | init_room(&bdev->aclRoom); | |||
491 | // init_room(new_bt_dev->scoRoom); | |||
492 | ||||
493 | list_init(&bdev->snetBufferRecycleTrash); | |||
494 | ||||
495 | // Allocate set and register the HCI device | |||
496 | if (btDevices != NULL__null) { | |||
497 | bluetooth_device* ndev; | |||
498 | // TODO: Fill the transport descriptor | |||
499 | err = btDevices->RegisterDriver(&bluetooth_hooks, &ndev); | |||
500 | ||||
501 | if (err == B_OK((int)0)) { | |||
502 | bdev->hdev = hdev = ndev->index; // Get the index | |||
503 | bdev->ndev = ndev; // Get the net_device | |||
504 | ||||
505 | } else { | |||
506 | hdev = bdev->num; // XXX: Lets try to go on | |||
507 | } | |||
508 | } else { | |||
509 | hdev = bdev->num; // XXX: Lets try to go on | |||
510 | } | |||
511 | ||||
512 | bdev->hdev = hdev; | |||
513 | ||||
514 | *cookie = bdev; | |||
515 | release_sem(bdev->lock); | |||
516 | ||||
517 | return B_OK((int)0); | |||
518 | ||||
519 | } | |||
520 | ||||
521 | ||||
522 | /* called when a client calls POSIX close() on the driver, but I/O | |||
523 | * requests may still be pending | |||
524 | */ | |||
525 | static status_t | |||
526 | device_close(void* cookie) | |||
527 | { | |||
528 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
529 | ||||
530 | int32 i; | |||
531 | void* item; | |||
532 | bt_usb_dev* bdev = (bt_usb_dev*)cookie; | |||
533 | ||||
534 | if (bdev == NULL__null) | |||
535 | panic("bad cookie"); | |||
536 | ||||
537 | // Clean queues | |||
538 | ||||
539 | if (bdev->connected == true) { | |||
540 | TRACE("%s: Cancelling queues...\n", __func__)dprintf("h2generic: " "%s: Cancelling queues...\n", __func__); | |||
541 | ||||
542 | if (bdev->intr_in_ep != NULL__null) | |||
543 | usb->cancel_queued_transfers(bdev->intr_in_ep->handle); | |||
544 | ||||
545 | if (bdev->bulk_in_ep!=NULL__null) | |||
546 | usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); | |||
547 | ||||
548 | if (bdev->bulk_out_ep!=NULL__null) | |||
549 | usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); | |||
550 | } | |||
551 | ||||
552 | // TX | |||
553 | for (i = 0; i < BT_DRIVER_TXCOVERAGE(1 + 1 + 0 + 0); i++) { | |||
554 | if (i == BT_COMMAND) { | |||
555 | while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL__null) | |||
556 | snb_free((snet_buffer*)item); | |||
557 | } else { | |||
558 | while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL__null) | |||
559 | nb_destroy((net_buffer*)item); | |||
560 | } | |||
561 | } | |||
562 | // RX | |||
563 | for (i = 0; i < BT_DRIVER_RXCOVERAGE(1 + 1 + 0 + 0); i++) { | |||
564 | nb_destroy(bdev->nbufferRx[i]); | |||
565 | } | |||
566 | snb_free(bdev->eventRx); | |||
567 | ||||
568 | purge_room(&bdev->eventRoom); | |||
569 | purge_room(&bdev->aclRoom); | |||
570 | ||||
571 | // Device no longer in our Stack | |||
572 | if (btDevices != NULL__null) | |||
573 | btDevices->UnregisterDriver(bdev->hdev); | |||
574 | ||||
575 | // unSet RUNNING | |||
576 | if (TEST_AND_CLEAR(&bdev->state, RUNNING)) { | |||
577 | ERROR("%s: %s not running?\n", __func__, bdev->name)dprintf("h2generic: " "%s: %s not running?\n", __func__, bdev ->name); | |||
578 | return B_ERROR(-1); | |||
579 | } | |||
580 | ||||
581 | return B_OK((int)0); | |||
582 | } | |||
583 | ||||
584 | ||||
585 | // Called after device_close(), when all pending I / O requests have returned | |||
586 | static status_t | |||
587 | device_free(void* cookie) | |||
588 | { | |||
589 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
590 | ||||
591 | status_t err = B_OK((int)0); | |||
592 | bt_usb_dev* bdev = (bt_usb_dev*)cookie; | |||
593 | ||||
594 | if (!bdev->connected) | |||
595 | kill_device(bdev); | |||
596 | ||||
597 | return err; | |||
598 | } | |||
599 | ||||
600 | ||||
601 | // implements the POSIX ioctl() | |||
602 | static status_t | |||
603 | device_control(void* cookie, uint32 msg, void* params, size_t size) | |||
604 | { | |||
605 | status_t err = B_ERROR(-1); | |||
606 | bt_usb_dev* bdev = (bt_usb_dev*)cookie; | |||
607 | snet_buffer* snbuf; | |||
608 | #if BT_DRIVER_SUPPORTS_ACL1 // ACL | |||
609 | int32 i; | |||
610 | #endif | |||
611 | ||||
612 | TOUCH(size)((void)(size)); | |||
613 | TRACE("%s: ioctl() opcode %" B_PRId32 " size %" B_PRIuSIZE ".\n", __func__,dprintf("h2generic: " "%s: ioctl() opcode %" "" "d" " size %" "l" "u" ".\n", __func__, msg, size) | |||
614 | msg, size)dprintf("h2generic: " "%s: ioctl() opcode %" "" "d" " size %" "l" "u" ".\n", __func__, msg, size); | |||
615 | ||||
616 | if (bdev == NULL__null) { | |||
617 | TRACE("%s: Bad cookie\n", __func__)dprintf("h2generic: " "%s: Bad cookie\n", __func__); | |||
618 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
619 | } | |||
620 | ||||
621 | if (params == NULL__null) { | |||
622 | TRACE("%s: Invalid pointer control\n", __func__)dprintf("h2generic: " "%s: Invalid pointer control\n", __func__ ); | |||
623 | return B_BAD_VALUE((-2147483647 - 1) + 5); | |||
624 | } | |||
625 | ||||
626 | acquire_sem(bdev->lock); | |||
627 | ||||
628 | switch (msg) { | |||
629 | case ISSUE_BT_COMMAND: | |||
630 | #ifdef BT_IOCTLS_PASS_SIZE | |||
631 | if (size == 0) { | |||
632 | TRACE("%s: Invalid size control\n", __func__)dprintf("h2generic: " "%s: Invalid size control\n", __func__); | |||
633 | err = B_BAD_VALUE((-2147483647 - 1) + 5); | |||
634 | break; | |||
635 | } | |||
636 | #else | |||
637 | size = (*((size_t*)params)); | |||
638 | (*(size_t**)¶ms)++; | |||
639 | #endif | |||
640 | ||||
641 | // TODO: Reuse from some TXcompleted queue | |||
642 | // snbuf = snb_create(size); | |||
643 | snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size); | |||
644 | snb_put(snbuf, params, size); | |||
645 | ||||
646 | err = submit_tx_command(bdev, snbuf); | |||
647 | TRACE("%s: command launched\n", __func__)dprintf("h2generic: " "%s: command launched\n", __func__); | |||
648 | break; | |||
649 | ||||
650 | case BT_UP: | |||
651 | ||||
652 | // EVENTS | |||
653 | err = submit_rx_event(bdev); | |||
654 | if (err != B_OK((int)0)) { | |||
655 | bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT)((bdev->state) & (~(1 << (ANCILLYANT)))); | |||
656 | ERROR("%s: Queuing failed device stops running\n", __func__)dprintf("h2generic: " "%s: Queuing failed device stops running\n" , __func__); | |||
657 | break; | |||
658 | } | |||
659 | ||||
660 | #if BT_DRIVER_SUPPORTS_ACL1 // ACL | |||
661 | for (i = 0; i < MAX_ACL_IN_WINDOW1; i++) { | |||
662 | err = submit_rx_acl(bdev); | |||
663 | if (err != B_OK((int)0) && i == 0) { | |||
664 | bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT)((bdev->state) & (~(1 << (ANCILLYANT)))); | |||
665 | // Set the flaq in the HCI world | |||
666 | ERROR("%s: Queuing failed device stops running\n",dprintf("h2generic: " "%s: Queuing failed device stops running\n" , __func__) | |||
667 | __func__)dprintf("h2generic: " "%s: Queuing failed device stops running\n" , __func__); | |||
668 | break; | |||
669 | } | |||
670 | } | |||
671 | #endif | |||
672 | ||||
673 | bdev->state = SET_BIT(bdev->state, RUNNING)((bdev->state) | (1 << (RUNNING))); | |||
674 | ||||
675 | #if BT_DRIVER_SUPPORTS_SCO0 | |||
676 | // TODO: SCO / eSCO | |||
677 | #endif | |||
678 | ||||
679 | ERROR("%s: Device online\n", __func__)dprintf("h2generic: " "%s: Device online\n", __func__); | |||
680 | break; | |||
681 | ||||
682 | case GET_STATS: | |||
683 | memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); | |||
684 | err = B_OK((int)0); | |||
685 | break; | |||
686 | ||||
687 | case GET_HCI_ID: | |||
688 | *(hci_id*)params = bdev->hdev; | |||
689 | err = B_OK((int)0); | |||
690 | break; | |||
691 | ||||
692 | ||||
693 | default: | |||
694 | ERROR("%s: Invalid opcode.\n", __func__)dprintf("h2generic: " "%s: Invalid opcode.\n", __func__); | |||
695 | err = B_DEV_INVALID_IOCTL(((-2147483647 - 1) + 0xa000) + 0); | |||
696 | break; | |||
697 | } | |||
698 | ||||
699 | release_sem(bdev->lock); | |||
700 | return err; | |||
701 | } | |||
702 | ||||
703 | ||||
704 | // implements the POSIX read() | |||
705 | static status_t | |||
706 | device_read(void* cookie, off_t pos, void* buffer, size_t* count) | |||
707 | { | |||
708 | TRACE("%s: Reading... count = %" B_PRIuSIZE "\n", __func__, *count)dprintf("h2generic: " "%s: Reading... count = %" "l" "u" "\n" , __func__, *count); | |||
709 | ||||
710 | *count = 0; | |||
711 | return B_OK((int)0); | |||
712 | } | |||
713 | ||||
714 | ||||
715 | // implements the POSIX write() | |||
716 | static status_t | |||
717 | device_write(void* cookie, off_t pos, const void* buffer, size_t* count) | |||
718 | { | |||
719 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
720 | ||||
721 | return B_ERROR(-1); | |||
722 | } | |||
723 | ||||
724 | ||||
725 | #if 0 | |||
726 | #pragma mark - | |||
727 | #endif | |||
728 | ||||
729 | ||||
730 | static int | |||
731 | dump_driver(int argc, char** argv) | |||
732 | { | |||
733 | int i; | |||
734 | snet_buffer* item = NULL__null; | |||
735 | ||||
736 | for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES16; i++) { | |||
737 | ||||
738 | if (bt_usb_devices[i] != NULL__null) { | |||
739 | kprintf("%s : \n", bt_usb_devices[i]->name); | |||
740 | kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n", | |||
741 | snb_packets(&bt_usb_devices[i]->eventRoom), | |||
742 | snb_packets(&bt_usb_devices[i]->aclRoom), | |||
743 | snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash)); | |||
744 | ||||
745 | while ((item = (snet_buffer*)list_get_next_item( | |||
746 | &bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL__null) | |||
747 | snb_dump(item); | |||
748 | } | |||
749 | } | |||
750 | ||||
751 | return 0; | |||
752 | } | |||
753 | ||||
754 | ||||
755 | // called each time the driver is loaded by the kernel | |||
756 | status_t | |||
757 | init_driver(void) | |||
758 | { | |||
759 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
760 | int j; | |||
761 | ||||
762 | if (get_module(BT_CORE_DATA_MODULE_NAME"bluetooth/btCoreData/v1", | |||
763 | (module_info**)&btCoreData) != B_OK((int)0)) { | |||
764 | ERROR("%s: cannot get module '%s'\n", __func__,dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , "bluetooth/btCoreData/v1") | |||
765 | BT_CORE_DATA_MODULE_NAME)dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , "bluetooth/btCoreData/v1"); | |||
766 | return B_ERROR(-1); | |||
767 | } | |||
768 | ||||
769 | // BT devices MODULE INITS | |||
770 | if (get_module(btDevices_name, (module_info**)&btDevices) != B_OK((int)0)) { | |||
771 | ERROR("%s: cannot get module '%s'\n", __func__, btDevices_name)dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , btDevices_name); | |||
772 | goto err_release3; | |||
773 | } | |||
774 | ||||
775 | // HCI MODULE INITS | |||
776 | if (get_module(hci_name, (module_info**)&hci) != B_OK((int)0)) { | |||
777 | ERROR("%s: cannot get module '%s'\n", __func__, hci_name)dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , hci_name); | |||
778 | #ifndef BT_SURVIVE_WITHOUT_HCI | |||
779 | goto err_release2; | |||
780 | #endif | |||
781 | } | |||
782 | ||||
783 | // USB MODULE INITS | |||
784 | if (get_module(usb_name, (module_info**)&usb) != B_OK((int)0)) { | |||
785 | ERROR("%s: cannot get module '%s'\n", __func__, usb_name)dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , usb_name); | |||
786 | goto err_release1; | |||
787 | } | |||
788 | ||||
789 | if (get_module(NET_BUFFER_MODULE_NAME"network/stack/buffer/v1", (module_info**)&nb) != B_OK((int)0)) { | |||
790 | ERROR("%s: cannot get module '%s'\n", __func__,dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , "network/stack/buffer/v1") | |||
791 | NET_BUFFER_MODULE_NAME)dprintf("h2generic: " "%s: cannot get module '%s'\n", __func__ , "network/stack/buffer/v1"); | |||
792 | #ifndef BT_SURVIVE_WITHOUT_NET_BUFFERS | |||
793 | goto err_release; | |||
794 | #endif | |||
795 | } | |||
796 | ||||
797 | // GENERAL INITS | |||
798 | dev_table_sem = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic" "dev_table_lock"); | |||
799 | if (dev_table_sem < 0) { | |||
800 | goto err; | |||
801 | } | |||
802 | ||||
803 | for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES16; j++) { | |||
804 | bt_usb_devices[j] = NULL__null; | |||
805 | } | |||
806 | ||||
807 | // Note: After here device_added and publish devices hooks are called | |||
808 | usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic", supported_devices, 1, NULL__null); | |||
809 | usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic", ¬ify_hooks); | |||
810 | ||||
811 | add_debugger_command("bth2generic", &dump_driver, | |||
812 | "Lists H2 Transport device info"); | |||
813 | ||||
814 | return B_OK((int)0); | |||
815 | ||||
816 | err: // Releasing | |||
817 | put_module(NET_BUFFER_MODULE_NAME"network/stack/buffer/v1"); | |||
818 | err_release: | |||
819 | put_module(usb_name); | |||
820 | err_release1: | |||
821 | put_module(hci_name); | |||
822 | #ifndef BT_SURVIVE_WITHOUT_HCI | |||
823 | err_release2: | |||
824 | #endif | |||
825 | put_module(btDevices_name); | |||
826 | err_release3: | |||
827 | put_module(BT_CORE_DATA_MODULE_NAME"bluetooth/btCoreData/v1"); | |||
828 | ||||
829 | return B_ERROR(-1); | |||
830 | } | |||
831 | ||||
832 | ||||
833 | // called just before the kernel unloads the driver | |||
834 | void | |||
835 | uninit_driver(void) | |||
836 | { | |||
837 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
838 | ||||
839 | int32 j; | |||
840 | ||||
841 | for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES16; j++) { | |||
842 | ||||
843 | if (publish_names[j] != NULL__null) | |||
844 | free(publish_names[j]); | |||
845 | ||||
846 | if (bt_usb_devices[j] != NULL__null) { | |||
847 | // if (connected_dev != NULL) { | |||
848 | // debugf("Device %p still exists.\n", connected_dev); | |||
849 | // } | |||
850 | ERROR("%s: %s still present?\n", __func__, bt_usb_devices[j]->name)dprintf("h2generic: " "%s: %s still present?\n", __func__, bt_usb_devices [j]->name); | |||
851 | kill_device(bt_usb_devices[j]); | |||
852 | } | |||
853 | } | |||
854 | ||||
855 | usb->uninstall_notify(BLUETOOTH_DEVICE_DEVFS_NAME"h2" "generic"); | |||
856 | ||||
857 | remove_debugger_command("bth2generic", &dump_driver); | |||
858 | ||||
859 | // Releasing modules | |||
860 | put_module(usb_name); | |||
861 | put_module(hci_name); | |||
862 | // TODO: netbuffers | |||
863 | ||||
864 | delete_sem(dev_table_sem); | |||
865 | } | |||
866 | ||||
867 | ||||
868 | const char** | |||
869 | publish_devices(void) | |||
870 | { | |||
871 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
872 | int32 j; | |||
873 | int32 i = 0; | |||
874 | ||||
875 | char* str; | |||
876 | ||||
877 | for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES16; j++) { | |||
878 | if (publish_names[j]) { | |||
879 | free(publish_names[j]); | |||
880 | publish_names[j] = NULL__null; | |||
881 | } | |||
882 | } | |||
883 | ||||
884 | acquire_sem(dev_table_sem); | |||
885 | for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES16; j++) { | |||
886 | if (bt_usb_devices[j] != NULL__null && bt_usb_devices[j]->connected) { | |||
887 | str = strdup(bt_usb_devices[j]->name); | |||
888 | if (str) { | |||
889 | publish_names[i++] = str; | |||
890 | TRACE("%s: publishing %s\n", __func__, bt_usb_devices[j]->name)dprintf("h2generic: " "%s: publishing %s\n", __func__, bt_usb_devices [j]->name); | |||
891 | } | |||
892 | } | |||
893 | } | |||
894 | release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); | |||
895 | ||||
896 | publish_names[i] = NULL__null; | |||
897 | TRACE("%s: published %" B_PRId32 " devices\n", __func__, i)dprintf("h2generic: " "%s: published %" "" "d" " devices\n", __func__ , i); | |||
898 | ||||
899 | // TODO: this method might make better memory use | |||
900 | // dev_names = (char**)malloc(sizeof(char*) * (dev_count + 1)); | |||
901 | // if (dev_names) { | |||
902 | // for (i = 0; i < MAX_NUM_DEVS; i++) { | |||
903 | // if ((dev != NULL) // dev + \n | |||
904 | // && (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH) + 2))) { | |||
905 | // sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num); | |||
906 | // debugf("publishing \"%s\"\n", dev_names[i]); | |||
907 | // } | |||
908 | // } | |||
909 | ||||
910 | return (const char**)publish_names; | |||
911 | } | |||
912 | ||||
913 | ||||
914 | static device_hooks hooks = { | |||
915 | device_open, | |||
916 | device_close, | |||
917 | device_free, | |||
918 | device_control, | |||
919 | device_read, | |||
920 | device_write, | |||
921 | NULL__null, | |||
922 | NULL__null, | |||
923 | NULL__null, | |||
924 | NULL__null | |||
925 | }; | |||
926 | ||||
927 | ||||
928 | device_hooks* | |||
929 | find_device(const char* name) | |||
930 | { | |||
931 | CALLED()dprintf("h2generic: " "h2generic: CALLED %s\n", __PRETTY_FUNCTION__ ); | |||
932 | ||||
933 | return &hooks; | |||
934 | } |