Blame view

drivers/bluetooth/bpa10x.c 10.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
  /*
   *
   *  Digianswer Bluetooth USB driver
   *
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
5
   *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   *
   *
   *  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
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/kernel.h>
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
24
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/types.h>
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
28
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  #include <linux/errno.h>
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
30
  #include <linux/skbuff.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  
  #include <linux/usb.h>
  
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
943d56b0a   Marcel Holtmann   [Bluetooth] Remov...
36
  #define VERSION "0.10"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
44
45
  
  static struct usb_device_id bpa10x_table[] = {
  	/* Tektronix BPA 100/105 (Digianswer) */
  	{ USB_DEVICE(0x08fd, 0x0002) },
  
  	{ }	/* Terminating entry */
  };
  
  MODULE_DEVICE_TABLE(usb, bpa10x_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  struct bpa10x_data {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
47
48
  	struct hci_dev    *hdev;
  	struct usb_device *udev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
50
51
  	struct usb_anchor tx_anchor;
  	struct usb_anchor rx_anchor;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
53
  	struct sk_buff *rx_skb[2];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  };
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
55
  #define HCI_VENDOR_HDR_SIZE 5
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  
  struct hci_vendor_hdr {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
58
59
60
  	__u8    type;
  	__le16  snum;
  	__le16  dlen;
81ca405ae   Gustavo F. Padovan   Bluetooth: Use __...
61
  } __packed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
63
  static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
65
66
67
68
69
70
71
72
73
  	struct bpa10x_data *data = hdev->driver_data;
  
  	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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
  
  	while (count) {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
76
77
78
  		struct sk_buff *skb = data->rx_skb[queue];
  		struct { __u8 type; int expect; } *scb;
  		int type, len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
80
81
82
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
  		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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  			skb = bt_skb_alloc(len, GFP_ATOMIC);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
123
124
125
  			if (!skb) {
  				BT_ERR("%s no memory for packet", hdev->name);
  				return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
128
  			skb->dev = (void *) hdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
130
  			data->rx_skb[queue] = skb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
132
133
134
135
136
  			scb = (void *) skb->cb;
  			scb->type = type;
  			scb->expect = len;
  		} else {
  			/* Continuation */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
138
139
  			scb = (void *) skb->cb;
  			len = scb->expect;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  		}
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
141
  		len = min(len, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
143
  		memcpy(skb_put(skb, len), buf, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
145
  		scb->expect -= len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
147
148
  		if (scb->expect == 0) {
  			/* Complete frame */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
150
  			data->rx_skb[queue] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
152
  			bt_cb(skb)->pkt_type = scb->type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
  			hci_recv_frame(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  		}
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
155
156
  
  		count -= len; buf += len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
  	}
  
  	return 0;
  }
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
161
  static void bpa10x_tx_complete(struct urb *urb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
163
164
  	struct sk_buff *skb = urb->context;
  	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
166
167
  	BT_DBG("%s urb %p status %d count %d", hdev->name,
  					urb, urb->status, urb->actual_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
169
170
171
172
173
  	if (!test_bit(HCI_RUNNING, &hdev->flags))
  		goto done;
  
  	if (!urb->status)
  		hdev->stat.byte_tx += urb->transfer_buffer_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	else
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
175
  		hdev->stat.err_tx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
177
178
  done:
  	kfree(urb->setup_packet);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
180
181
182
183
184
185
186
187
  	kfree_skb(skb);
  }
  
  static void bpa10x_rx_complete(struct urb *urb)
  {
  	struct hci_dev *hdev = urb->context;
  	struct bpa10x_data *data = hdev->driver_data;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
189
190
  	BT_DBG("%s urb %p status %d count %d", hdev->name,
  					urb, urb->status, urb->actual_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
192
193
  	if (!test_bit(HCI_RUNNING, &hdev->flags))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
195
196
197
198
199
200
201
  	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++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
  	}
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
203
204
205
206
207
208
209
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
  	}
  }
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
212
  static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
214
215
216
217
218
  	struct bpa10x_data *data = hdev->driver_data;
  	struct urb *urb;
  	unsigned char *buf;
  	unsigned int pipe;
  	int err, size = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
220
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
222
223
224
  	urb = usb_alloc_urb(0, GFP_KERNEL);
  	if (!urb)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
226
227
228
229
230
  	buf = kmalloc(size, GFP_KERNEL);
  	if (!buf) {
  		usb_free_urb(urb);
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
232
  	pipe = usb_rcvintpipe(data->udev, 0x81);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
234
235
  	usb_fill_int_urb(urb, data->udev, pipe, buf, size,
  						bpa10x_rx_complete, hdev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
237
  	urb->transfer_flags |= URB_FREE_BUFFER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
239
  	usb_anchor_urb(urb, &data->rx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
241
242
243
244
245
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	}
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
247
  	usb_free_urb(urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
249
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  }
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
251
  static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
  {
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
253
  	struct bpa10x_data *data = hdev->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  	struct urb *urb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  	unsigned char *buf;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
256
257
  	unsigned int pipe;
  	int err, size = 64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
259
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
261
  	urb = usb_alloc_urb(0, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  	if (!urb)
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
263
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
265
  	buf = kmalloc(size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
  	if (!buf) {
  		usb_free_urb(urb);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
268
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
  	}
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
270
  	pipe = usb_rcvbulkpipe(data->udev, 0x82);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
272
273
  	usb_fill_bulk_urb(urb, data->udev, pipe,
  					buf, size, bpa10x_rx_complete, hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
275
  	urb->transfer_flags |= URB_FREE_BUFFER;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
277
  	usb_anchor_urb(urb, &data->rx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
279
280
281
282
283
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	usb_free_urb(urb);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
286
287
  
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
  }
  
  static int bpa10x_open(struct hci_dev *hdev)
  {
  	struct bpa10x_data *data = hdev->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  	int err;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
294
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
296
297
  
  	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
  		return 0;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
298
299
300
  	err = bpa10x_submit_intr_urb(hdev);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
302
303
304
  	err = bpa10x_submit_bulk_urb(hdev);
  	if (err < 0)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
306
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
308
309
  error:
  	usb_kill_anchored_urbs(&data->rx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
311
  	clear_bit(HCI_RUNNING, &hdev->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
316
317
318
  
  	return err;
  }
  
  static int bpa10x_close(struct hci_dev *hdev)
  {
  	struct bpa10x_data *data = hdev->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
320
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
  
  	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
  		return 0;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
324
  	usb_kill_anchored_urbs(&data->rx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
326
327
328
329
330
331
  
  	return 0;
  }
  
  static int bpa10x_flush(struct hci_dev *hdev)
  {
  	struct bpa10x_data *data = hdev->driver_data;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
332
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
334
  	usb_kill_anchored_urbs(&data->tx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
337
338
339
340
341
  
  	return 0;
  }
  
  static int bpa10x_send_frame(struct sk_buff *skb)
  {
  	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
342
343
344
345
346
  	struct bpa10x_data *data = hdev->driver_data;
  	struct usb_ctrlrequest *dr;
  	struct urb *urb;
  	unsigned int pipe;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
348
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
  
  	if (!test_bit(HCI_RUNNING, &hdev->flags))
  		return -EBUSY;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
352
353
354
  	urb = usb_alloc_urb(0, GFP_ATOMIC);
  	if (!urb)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  
  	/* Prepend skb with frame type */
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
357
  	*skb_push(skb, 1) = bt_cb(skb)->pkt_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

0d48d9394   Marcel Holtmann   [Bluetooth]: Move...
359
  	switch (bt_cb(skb)->pkt_type) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  	case HCI_COMMAND_PKT:
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  		hdev->stat.cmd_tx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
  		break;
  
  	case HCI_ACLDATA_PKT:
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
381
382
383
384
  		pipe = usb_sndbulkpipe(data->udev, 0x02);
  
  		usb_fill_bulk_urb(urb, data->udev, pipe,
  				skb->data, skb->len, bpa10x_tx_complete, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  		hdev->stat.acl_tx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
387
388
  		break;
  
  	case HCI_SCODATA_PKT:
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
389
390
391
392
  		pipe = usb_sndbulkpipe(data->udev, 0x02);
  
  		usb_fill_bulk_urb(urb, data->udev, pipe,
  				skb->data, skb->len, bpa10x_tx_complete, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  		hdev->stat.sco_tx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
396
  	default:
cb7cd4293   Adrian Bunk   drivers/bluetooth...
397
  		usb_free_urb(urb);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
398
399
400
401
  		return -EILSEQ;
  	}
  
  	usb_anchor_urb(urb, &data->tx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
403
404
405
406
407
408
  	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);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
410
  	usb_free_urb(urb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
  
  	return 0;
  }
  
  static void bpa10x_destruct(struct hci_dev *hdev)
  {
  	struct bpa10x_data *data = hdev->driver_data;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
418
  	BT_DBG("%s", hdev->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

cbafe312e   Ilpo Järvinen   bpa10x: free sk_b...
420
421
  	kfree_skb(data->rx_skb[0]);
  	kfree_skb(data->rx_skb[1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
  	kfree(data);
  }
  
  static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  	struct bpa10x_data *data;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
428
  	struct hci_dev *hdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
  	int err;
  
  	BT_DBG("intf %p id %p", intf, id);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
432
  	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
  		return -ENODEV;
089b1dbbd   Deepak Saxena   [PATCH] bluetooth...
434
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
435
  	if (!data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
438
  	data->udev = interface_to_usbdev(intf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
440
441
  	init_usb_anchor(&data->tx_anchor);
  	init_usb_anchor(&data->rx_anchor);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
  
  	hdev = hci_alloc_dev();
  	if (!hdev) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
  		kfree(data);
  		return -ENOMEM;
  	}
c13854cef   Marcel Holtmann   Bluetooth: Conver...
448
  	hdev->bus = HCI_USB;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  	hdev->driver_data = data;
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
450
451
  
  	data->hdev = hdev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  	SET_HCIDEV_DEV(hdev, &intf->dev);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
453
454
455
456
457
  	hdev->open     = bpa10x_open;
  	hdev->close    = bpa10x_close;
  	hdev->flush    = bpa10x_flush;
  	hdev->send     = bpa10x_send_frame;
  	hdev->destruct = bpa10x_destruct;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
  
  	hdev->owner = THIS_MODULE;
7a9d40205   Marcel Holtmann   Bluetooth: Send H...
460
  	set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
  	err = hci_register_dev(hdev);
  	if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  		hci_free_dev(hdev);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
464
  		kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
468
469
470
471
472
473
474
475
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
  
  	BT_DBG("intf %p", intf);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
478
  	if (!data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
  		return;
  
  	usb_set_intfdata(intf, NULL);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
482
  	hci_unregister_dev(data->hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483

e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
484
  	hci_free_dev(data->hdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
  }
  
  static struct usb_driver bpa10x_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
494
495
  	.name		= "bpa10x",
  	.probe		= bpa10x_probe,
  	.disconnect	= bpa10x_disconnect,
  	.id_table	= bpa10x_table,
  };
  
  static int __init bpa10x_init(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
e24b21ec8   Marcel Holtmann   [Bluetooth] Chang...
497
  	return usb_register(&bpa10x_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
504
505
506
  }
  
  static void __exit bpa10x_exit(void)
  {
  	usb_deregister(&bpa10x_driver);
  }
  
  module_init(bpa10x_init);
  module_exit(bpa10x_exit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
  MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
  MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION);
  MODULE_VERSION(VERSION);
  MODULE_LICENSE("GPL");