brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · a69feb0 Raw
376 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *4 *  Generic Bluetooth SDIO driver5 *6 *  Copyright (C) 2007  Cambridge Silicon Radio Ltd.7 *  Copyright (C) 2007  Marcel Holtmann <marcel@holtmann.org>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/init.h>13#include <linux/slab.h>14#include <linux/types.h>15#include <linux/sched.h>16#include <linux/errno.h>17#include <linux/skbuff.h>18 19#include <linux/mmc/host.h>20#include <linux/mmc/sdio_ids.h>21#include <linux/mmc/sdio_func.h>22 23#include <net/bluetooth/bluetooth.h>24#include <net/bluetooth/hci_core.h>25 26#define VERSION "0.1"27 28static const struct sdio_device_id btsdio_table[] = {29	/* Generic Bluetooth Type-A SDIO device */30	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },31 32	/* Generic Bluetooth Type-B SDIO device */33	{ SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },34 35	{ }	/* Terminating entry */36};37 38MODULE_DEVICE_TABLE(sdio, btsdio_table);39 40struct btsdio_data {41	struct hci_dev   *hdev;42	struct sdio_func *func;43 44	struct work_struct work;45 46	struct sk_buff_head txq;47};48 49#define REG_RDAT     0x00	/* Receiver Data */50#define REG_TDAT     0x00	/* Transmitter Data */51#define REG_PC_RRT   0x10	/* Read Packet Control */52#define REG_PC_WRT   0x11	/* Write Packet Control */53#define REG_RTC_STAT 0x12	/* Retry Control Status */54#define REG_RTC_SET  0x12	/* Retry Control Set */55#define REG_INTRD    0x13	/* Interrupt Indication */56#define REG_CL_INTRD 0x13	/* Interrupt Clear */57#define REG_EN_INTRD 0x14	/* Interrupt Enable */58#define REG_MD_STAT  0x20	/* Bluetooth Mode Status */59#define REG_MD_SET   0x20	/* Bluetooth Mode Set */60 61static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)62{63	int err;64 65	BT_DBG("%s", data->hdev->name);66 67	/* Prepend Type-A header */68	skb_push(skb, 4);69	skb->data[0] = (skb->len & 0x0000ff);70	skb->data[1] = (skb->len & 0x00ff00) >> 8;71	skb->data[2] = (skb->len & 0xff0000) >> 16;72	skb->data[3] = hci_skb_pkt_type(skb);73 74	err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);75	if (err < 0) {76		skb_pull(skb, 4);77		sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);78		return err;79	}80 81	data->hdev->stat.byte_tx += skb->len;82 83	kfree_skb(skb);84 85	return 0;86}87 88static void btsdio_work(struct work_struct *work)89{90	struct btsdio_data *data = container_of(work, struct btsdio_data, work);91	struct sk_buff *skb;92	int err;93 94	BT_DBG("%s", data->hdev->name);95 96	sdio_claim_host(data->func);97 98	while ((skb = skb_dequeue(&data->txq))) {99		err = btsdio_tx_packet(data, skb);100		if (err < 0) {101			data->hdev->stat.err_tx++;102			skb_queue_head(&data->txq, skb);103			break;104		}105	}106 107	sdio_release_host(data->func);108}109 110static int btsdio_rx_packet(struct btsdio_data *data)111{112	u8 hdr[4] __attribute__ ((aligned(4)));113	struct sk_buff *skb;114	int err, len;115 116	BT_DBG("%s", data->hdev->name);117 118	err = sdio_readsb(data->func, hdr, REG_RDAT, 4);119	if (err < 0)120		return err;121 122	len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);123	if (len < 4 || len > 65543)124		return -EILSEQ;125 126	skb = bt_skb_alloc(len - 4, GFP_KERNEL);127	if (!skb) {128		/* Out of memory. Prepare a read retry and just129		 * return with the expectation that the next time130		 * we're called we'll have more memory.131		 */132		return -ENOMEM;133	}134 135	skb_put(skb, len - 4);136 137	err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);138	if (err < 0) {139		kfree_skb(skb);140		return err;141	}142 143	data->hdev->stat.byte_rx += len;144 145	switch (hdr[3]) {146	case HCI_EVENT_PKT:147	case HCI_ACLDATA_PKT:148	case HCI_SCODATA_PKT:149	case HCI_ISODATA_PKT:150		hci_skb_pkt_type(skb) = hdr[3];151		err = hci_recv_frame(data->hdev, skb);152		if (err < 0)153			return err;154		break;155	default:156		kfree_skb(skb);157		return -EINVAL;158	}159 160	sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);161 162	return 0;163}164 165static void btsdio_interrupt(struct sdio_func *func)166{167	struct btsdio_data *data = sdio_get_drvdata(func);168	int intrd;169 170	BT_DBG("%s", data->hdev->name);171 172	intrd = sdio_readb(func, REG_INTRD, NULL);173	if (intrd & 0x01) {174		sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);175 176		if (btsdio_rx_packet(data) < 0) {177			data->hdev->stat.err_rx++;178			sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);179		}180	}181}182 183static int btsdio_open(struct hci_dev *hdev)184{185	struct btsdio_data *data = hci_get_drvdata(hdev);186	int err;187 188	BT_DBG("%s", hdev->name);189 190	sdio_claim_host(data->func);191 192	err = sdio_enable_func(data->func);193	if (err < 0)194		goto release;195 196	err = sdio_claim_irq(data->func, btsdio_interrupt);197	if (err < 0) {198		sdio_disable_func(data->func);199		goto release;200	}201 202	if (data->func->class == SDIO_CLASS_BT_B)203		sdio_writeb(data->func, 0x00, REG_MD_SET, NULL);204 205	sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);206 207release:208	sdio_release_host(data->func);209 210	return err;211}212 213static int btsdio_close(struct hci_dev *hdev)214{215	struct btsdio_data *data = hci_get_drvdata(hdev);216 217	BT_DBG("%s", hdev->name);218 219	sdio_claim_host(data->func);220 221	sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);222 223	sdio_release_irq(data->func);224	sdio_disable_func(data->func);225 226	sdio_release_host(data->func);227 228	return 0;229}230 231static int btsdio_flush(struct hci_dev *hdev)232{233	struct btsdio_data *data = hci_get_drvdata(hdev);234 235	BT_DBG("%s", hdev->name);236 237	skb_queue_purge(&data->txq);238 239	return 0;240}241 242static int btsdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)243{244	struct btsdio_data *data = hci_get_drvdata(hdev);245 246	BT_DBG("%s", hdev->name);247 248	switch (hci_skb_pkt_type(skb)) {249	case HCI_COMMAND_PKT:250		hdev->stat.cmd_tx++;251		break;252 253	case HCI_ACLDATA_PKT:254		hdev->stat.acl_tx++;255		break;256 257	case HCI_SCODATA_PKT:258		hdev->stat.sco_tx++;259		break;260 261	default:262		return -EILSEQ;263	}264 265	skb_queue_tail(&data->txq, skb);266 267	schedule_work(&data->work);268 269	return 0;270}271 272static int btsdio_probe(struct sdio_func *func,273				const struct sdio_device_id *id)274{275	struct btsdio_data *data;276	struct hci_dev *hdev;277	struct sdio_func_tuple *tuple = func->tuples;278	int err;279 280	BT_DBG("func %p id %p class 0x%04x", func, id, func->class);281 282	while (tuple) {283		BT_DBG("code 0x%x size %d", tuple->code, tuple->size);284		tuple = tuple->next;285	}286 287	/* Broadcom devices soldered onto the PCB (non-removable) use an288	 * UART connection for Bluetooth, ignore the BT SDIO interface.289	 */290	if (func->vendor == SDIO_VENDOR_ID_BROADCOM &&291	    !mmc_card_is_removable(func->card->host)) {292		switch (func->device) {293		case SDIO_DEVICE_ID_BROADCOM_43341:294		case SDIO_DEVICE_ID_BROADCOM_43430:295		case SDIO_DEVICE_ID_BROADCOM_4345:296		case SDIO_DEVICE_ID_BROADCOM_43455:297		case SDIO_DEVICE_ID_BROADCOM_4356:298		case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:299			return -ENODEV;300		}301	}302 303	data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);304	if (!data)305		return -ENOMEM;306 307	data->func = func;308 309	INIT_WORK(&data->work, btsdio_work);310 311	skb_queue_head_init(&data->txq);312 313	hdev = hci_alloc_dev();314	if (!hdev)315		return -ENOMEM;316 317	hdev->bus = HCI_SDIO;318	hci_set_drvdata(hdev, data);319 320	data->hdev = hdev;321 322	SET_HCIDEV_DEV(hdev, &func->dev);323 324	hdev->open     = btsdio_open;325	hdev->close    = btsdio_close;326	hdev->flush    = btsdio_flush;327	hdev->send     = btsdio_send_frame;328 329	if (func->vendor == 0x0104 && func->device == 0x00c5)330		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);331 332	err = hci_register_dev(hdev);333	if (err < 0) {334		hci_free_dev(hdev);335		return err;336	}337 338	sdio_set_drvdata(func, data);339 340	return 0;341}342 343static void btsdio_remove(struct sdio_func *func)344{345	struct btsdio_data *data = sdio_get_drvdata(func);346	struct hci_dev *hdev;347 348	BT_DBG("func %p", func);349 350	if (!data)351		return;352 353	cancel_work_sync(&data->work);354	hdev = data->hdev;355 356	sdio_set_drvdata(func, NULL);357 358	hci_unregister_dev(hdev);359 360	hci_free_dev(hdev);361}362 363static struct sdio_driver btsdio_driver = {364	.name		= "btsdio",365	.probe		= btsdio_probe,366	.remove		= btsdio_remove,367	.id_table	= btsdio_table,368};369 370module_sdio_driver(btsdio_driver);371 372MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");373MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);374MODULE_VERSION(VERSION);375MODULE_LICENSE("GPL");376