bpa10x.c 10.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4
/*
 *
 *  Digianswer Bluetooth USB driver
 *
5
 *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/kernel.h>
25
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
26 27 28
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
29
#include <linux/sched.h>
Linus Torvalds's avatar
Linus Torvalds committed
30
#include <linux/errno.h>
31
#include <linux/skbuff.h>
Linus Torvalds's avatar
Linus Torvalds committed
32 33 34 35 36 37

#include <linux/usb.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

38
#define VERSION "0.10"
Linus Torvalds's avatar
Linus Torvalds committed
39 40 41 42 43 44 45 46 47 48 49

static struct usb_device_id bpa10x_table[] = {
	/* Tektronix BPA 100/105 (Digianswer) */
	{ USB_DEVICE(0x08fd, 0x0002) },

	{ }	/* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, bpa10x_table);

struct bpa10x_data {
50 51
	struct hci_dev    *hdev;
	struct usb_device *udev;
Linus Torvalds's avatar
Linus Torvalds committed
52

53 54
	struct usb_anchor tx_anchor;
	struct usb_anchor rx_anchor;
Linus Torvalds's avatar
Linus Torvalds committed
55

56
	struct sk_buff *rx_skb[2];
Linus Torvalds's avatar
Linus Torvalds committed
57 58
};

59
#define HCI_VENDOR_HDR_SIZE 5
Linus Torvalds's avatar
Linus Torvalds committed
60 61

struct hci_vendor_hdr {
62 63 64
	__u8    type;
	__le16  snum;
	__le16  dlen;
65
} __packed;
Linus Torvalds's avatar
Linus Torvalds committed
66

67
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
Linus Torvalds's avatar
Linus Torvalds committed
68
{
69
	struct bpa10x_data *data = hci_get_drvdata(hdev);
70 71 72 73 74 75 76 77

	BT_DBG("%s queue %d buffer %p count %d", hdev->name,
							queue, buf, count);

	if (queue < 0 || queue > 1)
		return -EILSEQ;

	hdev->stat.byte_rx += count;
Linus Torvalds's avatar
Linus Torvalds committed
78 79

	while (count) {
80 81 82
		struct sk_buff *skb = data->rx_skb[queue];
		struct { __u8 type; int expect; } *scb;
		int type, len = 0;
Linus Torvalds's avatar
Linus Torvalds committed
83

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
		if (!skb) {
			/* Start of the frame */

			type = *((__u8 *) buf);
			count--; buf++;

			switch (type) {
			case HCI_EVENT_PKT:
				if (count >= HCI_EVENT_HDR_SIZE) {
					struct hci_event_hdr *h = buf;
					len = HCI_EVENT_HDR_SIZE + h->plen;
				} else
					return -EILSEQ;
				break;

			case HCI_ACLDATA_PKT:
				if (count >= HCI_ACL_HDR_SIZE) {
					struct hci_acl_hdr *h = buf;
					len = HCI_ACL_HDR_SIZE +
							__le16_to_cpu(h->dlen);
				} else
					return -EILSEQ;
				break;

			case HCI_SCODATA_PKT:
				if (count >= HCI_SCO_HDR_SIZE) {
					struct hci_sco_hdr *h = buf;
					len = HCI_SCO_HDR_SIZE + h->dlen;
				} else
					return -EILSEQ;
				break;

			case HCI_VENDOR_PKT:
				if (count >= HCI_VENDOR_HDR_SIZE) {
					struct hci_vendor_hdr *h = buf;
					len = HCI_VENDOR_HDR_SIZE +
							__le16_to_cpu(h->dlen);
				} else
					return -EILSEQ;
				break;
Linus Torvalds's avatar
Linus Torvalds committed
124 125 126
			}

			skb = bt_skb_alloc(len, GFP_ATOMIC);
127 128 129
			if (!skb) {
				BT_ERR("%s no memory for packet", hdev->name);
				return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
130 131
			}

132
			skb->dev = (void *) hdev;
Linus Torvalds's avatar
Linus Torvalds committed
133

134
			data->rx_skb[queue] = skb;
Linus Torvalds's avatar
Linus Torvalds committed
135

136 137 138 139 140
			scb = (void *) skb->cb;
			scb->type = type;
			scb->expect = len;
		} else {
			/* Continuation */
Linus Torvalds's avatar
Linus Torvalds committed
141

142 143
			scb = (void *) skb->cb;
			len = scb->expect;
Linus Torvalds's avatar
Linus Torvalds committed
144 145
		}

146
		len = min(len, count);
Linus Torvalds's avatar
Linus Torvalds committed
147

148
		memcpy(skb_put(skb, len), buf, len);
Linus Torvalds's avatar
Linus Torvalds committed
149

150
		scb->expect -= len;
Linus Torvalds's avatar
Linus Torvalds committed
151

152 153
		if (scb->expect == 0) {
			/* Complete frame */
Linus Torvalds's avatar
Linus Torvalds committed
154

155
			data->rx_skb[queue] = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
156

157
			bt_cb(skb)->pkt_type = scb->type;
Linus Torvalds's avatar
Linus Torvalds committed
158 159
			hci_recv_frame(skb);
		}
160 161

		count -= len; buf += len;
Linus Torvalds's avatar
Linus Torvalds committed
162 163 164 165 166
	}

	return 0;
}

167
static void bpa10x_tx_complete(struct urb *urb)
Linus Torvalds's avatar
Linus Torvalds committed
168
{
169 170
	struct sk_buff *skb = urb->context;
	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
Linus Torvalds's avatar
Linus Torvalds committed
171

172 173
	BT_DBG("%s urb %p status %d count %d", hdev->name,
					urb, urb->status, urb->actual_length);
Linus Torvalds's avatar
Linus Torvalds committed
174

175 176 177 178 179
	if (!test_bit(HCI_RUNNING, &hdev->flags))
		goto done;

	if (!urb->status)
		hdev->stat.byte_tx += urb->transfer_buffer_length;
Linus Torvalds's avatar
Linus Torvalds committed
180
	else
181
		hdev->stat.err_tx++;
Linus Torvalds's avatar
Linus Torvalds committed
182

183 184
done:
	kfree(urb->setup_packet);
Linus Torvalds's avatar
Linus Torvalds committed
185

186 187 188 189 190 191
	kfree_skb(skb);
}

static void bpa10x_rx_complete(struct urb *urb)
{
	struct hci_dev *hdev = urb->context;
192
	struct bpa10x_data *data = hci_get_drvdata(hdev);
193
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
194

195 196
	BT_DBG("%s urb %p status %d count %d", hdev->name,
					urb, urb->status, urb->actual_length);
Linus Torvalds's avatar
Linus Torvalds committed
197

198 199
	if (!test_bit(HCI_RUNNING, &hdev->flags))
		return;
Linus Torvalds's avatar
Linus Torvalds committed
200

201 202 203 204 205 206 207
	if (urb->status == 0) {
		if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
						urb->transfer_buffer,
						urb->actual_length) < 0) {
			BT_ERR("%s corrupted event packet", hdev->name);
			hdev->stat.err_rx++;
		}
Linus Torvalds's avatar
Linus Torvalds committed
208 209
	}

210 211 212 213 214 215 216
	usb_anchor_urb(urb, &data->rx_anchor);

	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err < 0) {
		BT_ERR("%s urb %p failed to resubmit (%d)",
						hdev->name, urb, -err);
		usb_unanchor_urb(urb);
Linus Torvalds's avatar
Linus Torvalds committed
217 218 219
	}
}

220
static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
Linus Torvalds's avatar
Linus Torvalds committed
221
{
222
	struct bpa10x_data *data = hci_get_drvdata(hdev);
223 224 225 226
	struct urb *urb;
	unsigned char *buf;
	unsigned int pipe;
	int err, size = 16;
Linus Torvalds's avatar
Linus Torvalds committed
227

228
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
229

230 231 232
	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb)
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
233

234 235 236 237 238
	buf = kmalloc(size, GFP_KERNEL);
	if (!buf) {
		usb_free_urb(urb);
		return -ENOMEM;
	}
Linus Torvalds's avatar
Linus Torvalds committed
239

240
	pipe = usb_rcvintpipe(data->udev, 0x81);
Linus Torvalds's avatar
Linus Torvalds committed
241

242 243
	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
						bpa10x_rx_complete, hdev, 1);
Linus Torvalds's avatar
Linus Torvalds committed
244

245
	urb->transfer_flags |= URB_FREE_BUFFER;
Linus Torvalds's avatar
Linus Torvalds committed
246

247
	usb_anchor_urb(urb, &data->rx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
248

249 250 251 252 253
	err = usb_submit_urb(urb, GFP_KERNEL);
	if (err < 0) {
		BT_ERR("%s urb %p submission failed (%d)",
						hdev->name, urb, -err);
		usb_unanchor_urb(urb);
Linus Torvalds's avatar
Linus Torvalds committed
254 255
	}

256
	usb_free_urb(urb);
Linus Torvalds's avatar
Linus Torvalds committed
257

258
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
259 260
}

261
static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
Linus Torvalds's avatar
Linus Torvalds committed
262
{
263
	struct bpa10x_data *data = hci_get_drvdata(hdev);
Linus Torvalds's avatar
Linus Torvalds committed
264 265
	struct urb *urb;
	unsigned char *buf;
266 267
	unsigned int pipe;
	int err, size = 64;
Linus Torvalds's avatar
Linus Torvalds committed
268

269
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
270

271
	urb = usb_alloc_urb(0, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
272
	if (!urb)
273
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
274

275
	buf = kmalloc(size, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
276 277
	if (!buf) {
		usb_free_urb(urb);
278
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
279 280
	}

281
	pipe = usb_rcvbulkpipe(data->udev, 0x82);
Linus Torvalds's avatar
Linus Torvalds committed
282

283 284
	usb_fill_bulk_urb(urb, data->udev, pipe,
					buf, size, bpa10x_rx_complete, hdev);
Linus Torvalds's avatar
Linus Torvalds committed
285

286
	urb->transfer_flags |= URB_FREE_BUFFER;
Linus Torvalds's avatar
Linus Torvalds committed
287

288
	usb_anchor_urb(urb, &data->rx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
289

290 291 292 293 294
	err = usb_submit_urb(urb, GFP_KERNEL);
	if (err < 0) {
		BT_ERR("%s urb %p submission failed (%d)",
						hdev->name, urb, -err);
		usb_unanchor_urb(urb);
Linus Torvalds's avatar
Linus Torvalds committed
295 296 297
	}

	usb_free_urb(urb);
298 299

	return err;
Linus Torvalds's avatar
Linus Torvalds committed
300 301 302 303
}

static int bpa10x_open(struct hci_dev *hdev)
{
304
	struct bpa10x_data *data = hci_get_drvdata(hdev);
Linus Torvalds's avatar
Linus Torvalds committed
305 306
	int err;

307
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
308 309 310 311

	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
		return 0;

312 313 314
	err = bpa10x_submit_intr_urb(hdev);
	if (err < 0)
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
315

316 317 318
	err = bpa10x_submit_bulk_urb(hdev);
	if (err < 0)
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
319

320
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
321

322 323
error:
	usb_kill_anchored_urbs(&data->rx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
324

325
	clear_bit(HCI_RUNNING, &hdev->flags);
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328 329 330 331

	return err;
}

static int bpa10x_close(struct hci_dev *hdev)
{
332
	struct bpa10x_data *data = hci_get_drvdata(hdev);
Linus Torvalds's avatar
Linus Torvalds committed
333

334
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
335 336 337 338

	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
		return 0;

339
	usb_kill_anchored_urbs(&data->rx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
340 341 342 343 344 345

	return 0;
}

static int bpa10x_flush(struct hci_dev *hdev)
{
346
	struct bpa10x_data *data = hci_get_drvdata(hdev);
Linus Torvalds's avatar
Linus Torvalds committed
347

348
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
349

350
	usb_kill_anchored_urbs(&data->tx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
351 352 353 354 355 356 357

	return 0;
}

static int bpa10x_send_frame(struct sk_buff *skb)
{
	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
358
	struct bpa10x_data *data = hci_get_drvdata(hdev);
359 360 361 362
	struct usb_ctrlrequest *dr;
	struct urb *urb;
	unsigned int pipe;
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
363

364
	BT_DBG("%s", hdev->name);
Linus Torvalds's avatar
Linus Torvalds committed
365 366 367 368

	if (!test_bit(HCI_RUNNING, &hdev->flags))
		return -EBUSY;

369 370 371
	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb)
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
372 373

	/* Prepend skb with frame type */
374
	*skb_push(skb, 1) = bt_cb(skb)->pkt_type;
Linus Torvalds's avatar
Linus Torvalds committed
375

376
	switch (bt_cb(skb)->pkt_type) {
Linus Torvalds's avatar
Linus Torvalds committed
377
	case HCI_COMMAND_PKT:
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
		if (!dr) {
			usb_free_urb(urb);
			return -ENOMEM;
		}

		dr->bRequestType = USB_TYPE_VENDOR;
		dr->bRequest     = 0;
		dr->wIndex       = 0;
		dr->wValue       = 0;
		dr->wLength      = __cpu_to_le16(skb->len);

		pipe = usb_sndctrlpipe(data->udev, 0x00);

		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
				skb->data, skb->len, bpa10x_tx_complete, skb);

Linus Torvalds's avatar
Linus Torvalds committed
395 396 397 398
		hdev->stat.cmd_tx++;
		break;

	case HCI_ACLDATA_PKT:
399 400 401 402 403
		pipe = usb_sndbulkpipe(data->udev, 0x02);

		usb_fill_bulk_urb(urb, data->udev, pipe,
				skb->data, skb->len, bpa10x_tx_complete, skb);

Linus Torvalds's avatar
Linus Torvalds committed
404 405 406 407
		hdev->stat.acl_tx++;
		break;

	case HCI_SCODATA_PKT:
408 409 410 411 412
		pipe = usb_sndbulkpipe(data->udev, 0x02);

		usb_fill_bulk_urb(urb, data->udev, pipe,
				skb->data, skb->len, bpa10x_tx_complete, skb);

Linus Torvalds's avatar
Linus Torvalds committed
413 414 415
		hdev->stat.sco_tx++;
		break;

416
	default:
417
		usb_free_urb(urb);
418 419 420 421
		return -EILSEQ;
	}

	usb_anchor_urb(urb, &data->tx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
422

423 424 425 426 427 428
	err = usb_submit_urb(urb, GFP_ATOMIC);
	if (err < 0) {
		BT_ERR("%s urb %p submission failed", hdev->name, urb);
		kfree(urb->setup_packet);
		usb_unanchor_urb(urb);
	}
Linus Torvalds's avatar
Linus Torvalds committed
429

430
	usb_free_urb(urb);
Linus Torvalds's avatar
Linus Torvalds committed
431 432 433 434 435 436 437

	return 0;
}

static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct bpa10x_data *data;
438
	struct hci_dev *hdev;
Linus Torvalds's avatar
Linus Torvalds committed
439 440 441 442
	int err;

	BT_DBG("intf %p id %p", intf, id);

443
	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
Linus Torvalds's avatar
Linus Torvalds committed
444 445
		return -ENODEV;

446
	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
447
	if (!data)
Linus Torvalds's avatar
Linus Torvalds committed
448 449
		return -ENOMEM;

450
	data->udev = interface_to_usbdev(intf);
Linus Torvalds's avatar
Linus Torvalds committed
451

452 453
	init_usb_anchor(&data->tx_anchor);
	init_usb_anchor(&data->rx_anchor);
Linus Torvalds's avatar
Linus Torvalds committed
454 455

	hdev = hci_alloc_dev();
456
	if (!hdev)
Linus Torvalds's avatar
Linus Torvalds committed
457 458
		return -ENOMEM;

459
	hdev->bus = HCI_USB;
460
	hci_set_drvdata(hdev, data);
461 462 463

	data->hdev = hdev;

Linus Torvalds's avatar
Linus Torvalds committed
464 465
	SET_HCIDEV_DEV(hdev, &intf->dev);

466 467 468 469
	hdev->open     = bpa10x_open;
	hdev->close    = bpa10x_close;
	hdev->flush    = bpa10x_flush;
	hdev->send     = bpa10x_send_frame;
Linus Torvalds's avatar
Linus Torvalds committed
470

471
	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
472

Linus Torvalds's avatar
Linus Torvalds committed
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
	err = hci_register_dev(hdev);
	if (err < 0) {
		hci_free_dev(hdev);
		return err;
	}

	usb_set_intfdata(intf, data);

	return 0;
}

static void bpa10x_disconnect(struct usb_interface *intf)
{
	struct bpa10x_data *data = usb_get_intfdata(intf);

	BT_DBG("intf %p", intf);

490
	if (!data)
Linus Torvalds's avatar
Linus Torvalds committed
491 492 493 494
		return;

	usb_set_intfdata(intf, NULL);

495
	hci_unregister_dev(data->hdev);
Linus Torvalds's avatar
Linus Torvalds committed
496

497
	hci_free_dev(data->hdev);
498 499
	kfree_skb(data->rx_skb[0]);
	kfree_skb(data->rx_skb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
500 501 502 503 504 505 506
}

static struct usb_driver bpa10x_driver = {
	.name		= "bpa10x",
	.probe		= bpa10x_probe,
	.disconnect	= bpa10x_disconnect,
	.id_table	= bpa10x_table,
507
	.disable_hub_initiated_lpm = 1,
Linus Torvalds's avatar
Linus Torvalds committed
508 509
};

510
module_usb_driver(bpa10x_driver);
Linus Torvalds's avatar
Linus Torvalds committed
511 512 513 514 515

MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");