cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

btsdio.c (7999B)


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