brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 1fa58c0 Raw
446 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *4 *  Digianswer Bluetooth USB driver5 *6 *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@holtmann.org>7 */8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/init.h>12#include <linux/slab.h>13#include <linux/types.h>14#include <linux/sched.h>15#include <linux/errno.h>16#include <linux/skbuff.h>17 18#include <linux/usb.h>19 20#include <net/bluetooth/bluetooth.h>21#include <net/bluetooth/hci_core.h>22 23#include "h4_recv.h"24 25#define VERSION "0.11"26 27static const struct usb_device_id bpa10x_table[] = {28	/* Tektronix BPA 100/105 (Digianswer) */29	{ USB_DEVICE(0x08fd, 0x0002) },30 31	{ }	/* Terminating entry */32};33 34MODULE_DEVICE_TABLE(usb, bpa10x_table);35 36struct bpa10x_data {37	struct hci_dev    *hdev;38	struct usb_device *udev;39 40	struct usb_anchor tx_anchor;41	struct usb_anchor rx_anchor;42 43	struct sk_buff *rx_skb[2];44};45 46static void bpa10x_tx_complete(struct urb *urb)47{48	struct sk_buff *skb = urb->context;49	struct hci_dev *hdev = (struct hci_dev *) skb->dev;50 51	BT_DBG("%s urb %p status %d count %d", hdev->name,52					urb, urb->status, urb->actual_length);53 54	if (!test_bit(HCI_RUNNING, &hdev->flags))55		goto done;56 57	if (!urb->status)58		hdev->stat.byte_tx += urb->transfer_buffer_length;59	else60		hdev->stat.err_tx++;61 62done:63	kfree(urb->setup_packet);64 65	kfree_skb(skb);66}67 68#define HCI_VENDOR_HDR_SIZE 569 70#define HCI_RECV_VENDOR \71	.type = HCI_VENDOR_PKT, \72	.hlen = HCI_VENDOR_HDR_SIZE, \73	.loff = 3, \74	.lsize = 2, \75	.maxlen = HCI_MAX_FRAME_SIZE76 77static const struct h4_recv_pkt bpa10x_recv_pkts[] = {78	{ H4_RECV_ACL,     .recv = hci_recv_frame },79	{ H4_RECV_SCO,     .recv = hci_recv_frame },80	{ H4_RECV_EVENT,   .recv = hci_recv_frame },81	{ HCI_RECV_VENDOR, .recv = hci_recv_diag  },82};83 84static void bpa10x_rx_complete(struct urb *urb)85{86	struct hci_dev *hdev = urb->context;87	struct bpa10x_data *data = hci_get_drvdata(hdev);88	int err;89 90	BT_DBG("%s urb %p status %d count %d", hdev->name,91					urb, urb->status, urb->actual_length);92 93	if (!test_bit(HCI_RUNNING, &hdev->flags))94		return;95 96	if (urb->status == 0) {97		bool idx = usb_pipebulk(urb->pipe);98 99		data->rx_skb[idx] = h4_recv_buf(hdev, data->rx_skb[idx],100						urb->transfer_buffer,101						urb->actual_length,102						bpa10x_recv_pkts,103						ARRAY_SIZE(bpa10x_recv_pkts));104		if (IS_ERR(data->rx_skb[idx])) {105			bt_dev_err(hdev, "corrupted event packet");106			hdev->stat.err_rx++;107			data->rx_skb[idx] = NULL;108		}109	}110 111	usb_anchor_urb(urb, &data->rx_anchor);112 113	err = usb_submit_urb(urb, GFP_ATOMIC);114	if (err < 0) {115		bt_dev_err(hdev, "urb %p failed to resubmit (%d)", urb, -err);116		usb_unanchor_urb(urb);117	}118}119 120static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)121{122	struct bpa10x_data *data = hci_get_drvdata(hdev);123	struct urb *urb;124	unsigned char *buf;125	unsigned int pipe;126	int err, size = 16;127 128	BT_DBG("%s", hdev->name);129 130	urb = usb_alloc_urb(0, GFP_KERNEL);131	if (!urb)132		return -ENOMEM;133 134	buf = kmalloc(size, GFP_KERNEL);135	if (!buf) {136		usb_free_urb(urb);137		return -ENOMEM;138	}139 140	pipe = usb_rcvintpipe(data->udev, 0x81);141 142	usb_fill_int_urb(urb, data->udev, pipe, buf, size,143						bpa10x_rx_complete, hdev, 1);144 145	urb->transfer_flags |= URB_FREE_BUFFER;146 147	usb_anchor_urb(urb, &data->rx_anchor);148 149	err = usb_submit_urb(urb, GFP_KERNEL);150	if (err < 0) {151		bt_dev_err(hdev, "urb %p submission failed (%d)", urb, -err);152		usb_unanchor_urb(urb);153	}154 155	usb_free_urb(urb);156 157	return err;158}159 160static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)161{162	struct bpa10x_data *data = hci_get_drvdata(hdev);163	struct urb *urb;164	unsigned char *buf;165	unsigned int pipe;166	int err, size = 64;167 168	BT_DBG("%s", hdev->name);169 170	urb = usb_alloc_urb(0, GFP_KERNEL);171	if (!urb)172		return -ENOMEM;173 174	buf = kmalloc(size, GFP_KERNEL);175	if (!buf) {176		usb_free_urb(urb);177		return -ENOMEM;178	}179 180	pipe = usb_rcvbulkpipe(data->udev, 0x82);181 182	usb_fill_bulk_urb(urb, data->udev, pipe,183					buf, size, bpa10x_rx_complete, hdev);184 185	urb->transfer_flags |= URB_FREE_BUFFER;186 187	usb_anchor_urb(urb, &data->rx_anchor);188 189	err = usb_submit_urb(urb, GFP_KERNEL);190	if (err < 0) {191		bt_dev_err(hdev, "urb %p submission failed (%d)", urb, -err);192		usb_unanchor_urb(urb);193	}194 195	usb_free_urb(urb);196 197	return err;198}199 200static int bpa10x_open(struct hci_dev *hdev)201{202	struct bpa10x_data *data = hci_get_drvdata(hdev);203	int err;204 205	BT_DBG("%s", hdev->name);206 207	err = bpa10x_submit_intr_urb(hdev);208	if (err < 0)209		goto error;210 211	err = bpa10x_submit_bulk_urb(hdev);212	if (err < 0)213		goto error;214 215	return 0;216 217error:218	usb_kill_anchored_urbs(&data->rx_anchor);219 220	return err;221}222 223static int bpa10x_close(struct hci_dev *hdev)224{225	struct bpa10x_data *data = hci_get_drvdata(hdev);226 227	BT_DBG("%s", hdev->name);228 229	usb_kill_anchored_urbs(&data->rx_anchor);230 231	return 0;232}233 234static int bpa10x_flush(struct hci_dev *hdev)235{236	struct bpa10x_data *data = hci_get_drvdata(hdev);237 238	BT_DBG("%s", hdev->name);239 240	usb_kill_anchored_urbs(&data->tx_anchor);241 242	return 0;243}244 245static int bpa10x_setup(struct hci_dev *hdev)246{247	static const u8 req[] = { 0x07 };248	struct sk_buff *skb;249 250	BT_DBG("%s", hdev->name);251 252	/* Read revision string */253	skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);254	if (IS_ERR(skb))255		return PTR_ERR(skb);256 257	bt_dev_info(hdev, "%s", (char *)(skb->data + 1));258 259	hci_set_fw_info(hdev, "%s", skb->data + 1);260 261	kfree_skb(skb);262	return 0;263}264 265static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb)266{267	struct bpa10x_data *data = hci_get_drvdata(hdev);268	struct usb_ctrlrequest *dr;269	struct urb *urb;270	unsigned int pipe;271	int err;272 273	BT_DBG("%s", hdev->name);274 275	skb->dev = (void *) hdev;276 277	urb = usb_alloc_urb(0, GFP_KERNEL);278	if (!urb)279		return -ENOMEM;280 281	/* Prepend skb with frame type */282	*(u8 *)skb_push(skb, 1) = hci_skb_pkt_type(skb);283 284	switch (hci_skb_pkt_type(skb)) {285	case HCI_COMMAND_PKT:286		dr = kmalloc(sizeof(*dr), GFP_KERNEL);287		if (!dr) {288			usb_free_urb(urb);289			return -ENOMEM;290		}291 292		dr->bRequestType = USB_TYPE_VENDOR;293		dr->bRequest     = 0;294		dr->wIndex       = 0;295		dr->wValue       = 0;296		dr->wLength      = __cpu_to_le16(skb->len);297 298		pipe = usb_sndctrlpipe(data->udev, 0x00);299 300		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,301				skb->data, skb->len, bpa10x_tx_complete, skb);302 303		hdev->stat.cmd_tx++;304		break;305 306	case HCI_ACLDATA_PKT:307		pipe = usb_sndbulkpipe(data->udev, 0x02);308 309		usb_fill_bulk_urb(urb, data->udev, pipe,310				skb->data, skb->len, bpa10x_tx_complete, skb);311 312		hdev->stat.acl_tx++;313		break;314 315	case HCI_SCODATA_PKT:316		pipe = usb_sndbulkpipe(data->udev, 0x02);317 318		usb_fill_bulk_urb(urb, data->udev, pipe,319				skb->data, skb->len, bpa10x_tx_complete, skb);320 321		hdev->stat.sco_tx++;322		break;323 324	default:325		usb_free_urb(urb);326		return -EILSEQ;327	}328 329	usb_anchor_urb(urb, &data->tx_anchor);330 331	err = usb_submit_urb(urb, GFP_KERNEL);332	if (err < 0) {333		bt_dev_err(hdev, "urb %p submission failed", urb);334		kfree(urb->setup_packet);335		usb_unanchor_urb(urb);336	}337 338	usb_free_urb(urb);339 340	return err;341}342 343static int bpa10x_set_diag(struct hci_dev *hdev, bool enable)344{345	const u8 req[] = { 0x00, enable };346	struct sk_buff *skb;347 348	BT_DBG("%s", hdev->name);349 350	if (!test_bit(HCI_RUNNING, &hdev->flags))351		return -ENETDOWN;352 353	/* Enable sniffer operation */354	skb = __hci_cmd_sync(hdev, 0xfc0e, sizeof(req), req, HCI_INIT_TIMEOUT);355	if (IS_ERR(skb))356		return PTR_ERR(skb);357 358	kfree_skb(skb);359	return 0;360}361 362static int bpa10x_probe(struct usb_interface *intf,363			const struct usb_device_id *id)364{365	struct bpa10x_data *data;366	struct hci_dev *hdev;367	int err;368 369	BT_DBG("intf %p id %p", intf, id);370 371	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)372		return -ENODEV;373 374	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);375	if (!data)376		return -ENOMEM;377 378	data->udev = interface_to_usbdev(intf);379 380	init_usb_anchor(&data->tx_anchor);381	init_usb_anchor(&data->rx_anchor);382 383	hdev = hci_alloc_dev();384	if (!hdev)385		return -ENOMEM;386 387	hdev->bus = HCI_USB;388	hci_set_drvdata(hdev, data);389 390	data->hdev = hdev;391 392	SET_HCIDEV_DEV(hdev, &intf->dev);393 394	hdev->open     = bpa10x_open;395	hdev->close    = bpa10x_close;396	hdev->flush    = bpa10x_flush;397	hdev->setup    = bpa10x_setup;398	hdev->send     = bpa10x_send_frame;399	hdev->set_diag = bpa10x_set_diag;400 401	set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);402 403	err = hci_register_dev(hdev);404	if (err < 0) {405		hci_free_dev(hdev);406		return err;407	}408 409	usb_set_intfdata(intf, data);410 411	return 0;412}413 414static void bpa10x_disconnect(struct usb_interface *intf)415{416	struct bpa10x_data *data = usb_get_intfdata(intf);417 418	BT_DBG("intf %p", intf);419 420	if (!data)421		return;422 423	usb_set_intfdata(intf, NULL);424 425	hci_unregister_dev(data->hdev);426 427	hci_free_dev(data->hdev);428	kfree_skb(data->rx_skb[0]);429	kfree_skb(data->rx_skb[1]);430}431 432static struct usb_driver bpa10x_driver = {433	.name		= "bpa10x",434	.probe		= bpa10x_probe,435	.disconnect	= bpa10x_disconnect,436	.id_table	= bpa10x_table,437	.disable_hub_initiated_lpm = 1,438};439 440module_usb_driver(bpa10x_driver);441 442MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");443MODULE_DESCRIPTION("Digianswer Bluetooth USB driver ver " VERSION);444MODULE_VERSION(VERSION);445MODULE_LICENSE("GPL");446