bpa10x.c 10.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4
/*
 *
 *  Digianswer Bluetooth USB driver
 *
5
 *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
L
Linus Torvalds 已提交
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>
L
Linus Torvalds 已提交
26 27 28
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
29
#include <linux/sched.h>
L
Linus Torvalds 已提交
30
#include <linux/errno.h>
31
#include <linux/skbuff.h>
L
Linus Torvalds 已提交
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"
L
Linus Torvalds 已提交
39

40
static const struct usb_device_id bpa10x_table[] = {
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49
	/* 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;
L
Linus Torvalds 已提交
52

53 54
	struct usb_anchor tx_anchor;
	struct usb_anchor rx_anchor;
L
Linus Torvalds 已提交
55

56
	struct sk_buff *rx_skb[2];
L
Linus Torvalds 已提交
57 58
};

59
#define HCI_VENDOR_HDR_SIZE 5
L
Linus Torvalds 已提交
60 61

struct hci_vendor_hdr {
62 63 64
	__u8    type;
	__le16  snum;
	__le16  dlen;
65
} __packed;
L
Linus Torvalds 已提交
66

67
static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
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;
L
Linus Torvalds 已提交
130 131
			}

132
			data->rx_skb[queue] = skb;
L
Linus Torvalds 已提交
133

134 135 136 137 138
			scb = (void *) skb->cb;
			scb->type = type;
			scb->expect = len;
		} else {
			/* Continuation */
L
Linus Torvalds 已提交
139

140 141
			scb = (void *) skb->cb;
			len = scb->expect;
L
Linus Torvalds 已提交
142 143
		}

144
		len = min(len, count);
L
Linus Torvalds 已提交
145

146
		memcpy(skb_put(skb, len), buf, len);
L
Linus Torvalds 已提交
147

148
		scb->expect -= len;
L
Linus Torvalds 已提交
149

150 151
		if (scb->expect == 0) {
			/* Complete frame */
L
Linus Torvalds 已提交
152

153
			data->rx_skb[queue] = NULL;
L
Linus Torvalds 已提交
154

155
			bt_cb(skb)->pkt_type = scb->type;
156
			hci_recv_frame(hdev, skb);
L
Linus Torvalds 已提交
157
		}
158 159

		count -= len; buf += len;
L
Linus Torvalds 已提交
160 161 162 163 164
	}

	return 0;
}

165
static void bpa10x_tx_complete(struct urb *urb)
L
Linus Torvalds 已提交
166
{
167 168
	struct sk_buff *skb = urb->context;
	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
L
Linus Torvalds 已提交
169

170 171
	BT_DBG("%s urb %p status %d count %d", hdev->name,
					urb, urb->status, urb->actual_length);
L
Linus Torvalds 已提交
172

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

	if (!urb->status)
		hdev->stat.byte_tx += urb->transfer_buffer_length;
L
Linus Torvalds 已提交
178
	else
179
		hdev->stat.err_tx++;
L
Linus Torvalds 已提交
180

181 182
done:
	kfree(urb->setup_packet);
L
Linus Torvalds 已提交
183

184 185 186 187 188 189
	kfree_skb(skb);
}

static void bpa10x_rx_complete(struct urb *urb)
{
	struct hci_dev *hdev = urb->context;
190
	struct bpa10x_data *data = hci_get_drvdata(hdev);
191
	int err;
L
Linus Torvalds 已提交
192

193 194
	BT_DBG("%s urb %p status %d count %d", hdev->name,
					urb, urb->status, urb->actual_length);
L
Linus Torvalds 已提交
195

196 197
	if (!test_bit(HCI_RUNNING, &hdev->flags))
		return;
L
Linus Torvalds 已提交
198

199 200 201 202 203 204 205
	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++;
		}
L
Linus Torvalds 已提交
206 207
	}

208 209 210 211 212 213 214
	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);
L
Linus Torvalds 已提交
215 216 217
	}
}

218
static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
L
Linus Torvalds 已提交
219
{
220
	struct bpa10x_data *data = hci_get_drvdata(hdev);
221 222 223 224
	struct urb *urb;
	unsigned char *buf;
	unsigned int pipe;
	int err, size = 16;
L
Linus Torvalds 已提交
225

226
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
227

228 229 230
	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb)
		return -ENOMEM;
L
Linus Torvalds 已提交
231

232 233 234 235 236
	buf = kmalloc(size, GFP_KERNEL);
	if (!buf) {
		usb_free_urb(urb);
		return -ENOMEM;
	}
L
Linus Torvalds 已提交
237

238
	pipe = usb_rcvintpipe(data->udev, 0x81);
L
Linus Torvalds 已提交
239

240 241
	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
						bpa10x_rx_complete, hdev, 1);
L
Linus Torvalds 已提交
242

243
	urb->transfer_flags |= URB_FREE_BUFFER;
L
Linus Torvalds 已提交
244

245
	usb_anchor_urb(urb, &data->rx_anchor);
L
Linus Torvalds 已提交
246

247 248 249 250 251
	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);
L
Linus Torvalds 已提交
252 253
	}

254
	usb_free_urb(urb);
L
Linus Torvalds 已提交
255

256
	return err;
L
Linus Torvalds 已提交
257 258
}

259
static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
L
Linus Torvalds 已提交
260
{
261
	struct bpa10x_data *data = hci_get_drvdata(hdev);
L
Linus Torvalds 已提交
262 263
	struct urb *urb;
	unsigned char *buf;
264 265
	unsigned int pipe;
	int err, size = 64;
L
Linus Torvalds 已提交
266

267
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
268

269
	urb = usb_alloc_urb(0, GFP_KERNEL);
L
Linus Torvalds 已提交
270
	if (!urb)
271
		return -ENOMEM;
L
Linus Torvalds 已提交
272

273
	buf = kmalloc(size, GFP_KERNEL);
L
Linus Torvalds 已提交
274 275
	if (!buf) {
		usb_free_urb(urb);
276
		return -ENOMEM;
L
Linus Torvalds 已提交
277 278
	}

279
	pipe = usb_rcvbulkpipe(data->udev, 0x82);
L
Linus Torvalds 已提交
280

281 282
	usb_fill_bulk_urb(urb, data->udev, pipe,
					buf, size, bpa10x_rx_complete, hdev);
L
Linus Torvalds 已提交
283

284
	urb->transfer_flags |= URB_FREE_BUFFER;
L
Linus Torvalds 已提交
285

286
	usb_anchor_urb(urb, &data->rx_anchor);
L
Linus Torvalds 已提交
287

288 289 290 291 292
	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);
L
Linus Torvalds 已提交
293 294 295
	}

	usb_free_urb(urb);
296 297

	return err;
L
Linus Torvalds 已提交
298 299 300 301
}

static int bpa10x_open(struct hci_dev *hdev)
{
302
	struct bpa10x_data *data = hci_get_drvdata(hdev);
L
Linus Torvalds 已提交
303 304
	int err;

305
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
306

307 308 309
	err = bpa10x_submit_intr_urb(hdev);
	if (err < 0)
		goto error;
L
Linus Torvalds 已提交
310

311 312 313
	err = bpa10x_submit_bulk_urb(hdev);
	if (err < 0)
		goto error;
L
Linus Torvalds 已提交
314

315
	return 0;
L
Linus Torvalds 已提交
316

317 318
error:
	usb_kill_anchored_urbs(&data->rx_anchor);
L
Linus Torvalds 已提交
319 320 321 322 323 324

	return err;
}

static int bpa10x_close(struct hci_dev *hdev)
{
325
	struct bpa10x_data *data = hci_get_drvdata(hdev);
L
Linus Torvalds 已提交
326

327
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
328

329
	usb_kill_anchored_urbs(&data->rx_anchor);
L
Linus Torvalds 已提交
330 331 332 333 334 335

	return 0;
}

static int bpa10x_flush(struct hci_dev *hdev)
{
336
	struct bpa10x_data *data = hci_get_drvdata(hdev);
L
Linus Torvalds 已提交
337

338
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
339

340
	usb_kill_anchored_urbs(&data->tx_anchor);
L
Linus Torvalds 已提交
341 342 343 344

	return 0;
}

345
static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
L
Linus Torvalds 已提交
346
{
347
	struct bpa10x_data *data = hci_get_drvdata(hdev);
348 349 350 351
	struct usb_ctrlrequest *dr;
	struct urb *urb;
	unsigned int pipe;
	int err;
L
Linus Torvalds 已提交
352

353
	BT_DBG("%s", hdev->name);
L
Linus Torvalds 已提交
354

355 356
	skb->dev = (void *) hdev;

357 358 359
	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb)
		return -ENOMEM;
L
Linus Torvalds 已提交
360 361

	/* Prepend skb with frame type */
362
	*skb_push(skb, 1) = bt_cb(skb)->pkt_type;
L
Linus Torvalds 已提交
363

364
	switch (bt_cb(skb)->pkt_type) {
L
Linus Torvalds 已提交
365
	case HCI_COMMAND_PKT:
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
		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);

L
Linus Torvalds 已提交
383 384 385 386
		hdev->stat.cmd_tx++;
		break;

	case HCI_ACLDATA_PKT:
387 388 389 390 391
		pipe = usb_sndbulkpipe(data->udev, 0x02);

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

L
Linus Torvalds 已提交
392 393 394 395
		hdev->stat.acl_tx++;
		break;

	case HCI_SCODATA_PKT:
396 397 398 399 400
		pipe = usb_sndbulkpipe(data->udev, 0x02);

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

L
Linus Torvalds 已提交
401 402 403
		hdev->stat.sco_tx++;
		break;

404
	default:
405
		usb_free_urb(urb);
406 407 408 409
		return -EILSEQ;
	}

	usb_anchor_urb(urb, &data->tx_anchor);
L
Linus Torvalds 已提交
410

411 412 413 414 415 416
	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);
	}
L
Linus Torvalds 已提交
417

418
	usb_free_urb(urb);
L
Linus Torvalds 已提交
419 420 421 422 423 424 425

	return 0;
}

static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct bpa10x_data *data;
426
	struct hci_dev *hdev;
L
Linus Torvalds 已提交
427 428 429 430
	int err;

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

431
	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
L
Linus Torvalds 已提交
432 433
		return -ENODEV;

434
	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
435
	if (!data)
L
Linus Torvalds 已提交
436 437
		return -ENOMEM;

438
	data->udev = interface_to_usbdev(intf);
L
Linus Torvalds 已提交
439

440 441
	init_usb_anchor(&data->tx_anchor);
	init_usb_anchor(&data->rx_anchor);
L
Linus Torvalds 已提交
442 443

	hdev = hci_alloc_dev();
444
	if (!hdev)
L
Linus Torvalds 已提交
445 446
		return -ENOMEM;

447
	hdev->bus = HCI_USB;
448
	hci_set_drvdata(hdev, data);
449 450 451

	data->hdev = hdev;

L
Linus Torvalds 已提交
452 453
	SET_HCIDEV_DEV(hdev, &intf->dev);

454 455 456 457
	hdev->open     = bpa10x_open;
	hdev->close    = bpa10x_close;
	hdev->flush    = bpa10x_flush;
	hdev->send     = bpa10x_send_frame;
L
Linus Torvalds 已提交
458

459
	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
460

L
Linus Torvalds 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
	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);

478
	if (!data)
L
Linus Torvalds 已提交
479 480 481 482
		return;

	usb_set_intfdata(intf, NULL);

483
	hci_unregister_dev(data->hdev);
L
Linus Torvalds 已提交
484

485
	hci_free_dev(data->hdev);
486 487
	kfree_skb(data->rx_skb[0]);
	kfree_skb(data->rx_skb[1]);
L
Linus Torvalds 已提交
488 489 490 491 492 493 494
}

static struct usb_driver bpa10x_driver = {
	.name		= "bpa10x",
	.probe		= bpa10x_probe,
	.disconnect	= bpa10x_disconnect,
	.id_table	= bpa10x_table,
495
	.disable_hub_initiated_lpm = 1,
L
Linus Torvalds 已提交
496 497
};

498
module_usb_driver(bpa10x_driver);
L
Linus Torvalds 已提交
499 500 501 502 503

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