···8282 - info on the Block I/O (BIO) layer.8383blockdev/8484 - info on block devices & drivers8585+btmrvl.txt8686+ - info on Marvell Bluetooth driver usage.8587cachetlb.txt8688 - describes the cache/TLB flushing interfaces Linux uses.8789cdrom/
+119
Documentation/btmrvl.txt
···11+=======================================================================22+ README for btmrvl driver33+=======================================================================44+55+66+All commands are used via debugfs interface.77+88+=====================99+Set/get driver configurations:1010+1111+Path: /debug/btmrvl/config/1212+1313+gpiogap=[n]1414+hscfgcmd1515+ These commands are used to configure the host sleep parameters.1616+ bit 8:0 -- Gap1717+ bit 16:8 -- GPIO1818+1919+ where GPIO is the pin number of GPIO used to wake up the host.2020+ It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface2121+ wakeup will be used instead).2222+2323+ where Gap is the gap in milli seconds between wakeup signal and2424+ wakeup event, or 0xff for special host sleep setting.2525+2626+ Usage:2727+ # Use SDIO interface to wake up the host and set GAP to 0x80:2828+ echo 0xff80 > /debug/btmrvl/config/gpiogap2929+ echo 1 > /debug/btmrvl/config/hscfgcmd3030+3131+ # Use GPIO pin #3 to wake up the host and set GAP to 0xff:3232+ echo 0x03ff > /debug/btmrvl/config/gpiogap3333+ echo 1 > /debug/btmrvl/config/hscfgcmd3434+3535+psmode=[n]3636+pscmd3737+ These commands are used to enable/disable auto sleep mode3838+3939+ where the option is:4040+ 1 -- Enable auto sleep mode4141+ 0 -- Disable auto sleep mode4242+4343+ Usage:4444+ # Enable auto sleep mode4545+ echo 1 > /debug/btmrvl/config/psmode4646+ echo 1 > /debug/btmrvl/config/pscmd4747+4848+ # Disable auto sleep mode4949+ echo 0 > /debug/btmrvl/config/psmode5050+ echo 1 > /debug/btmrvl/config/pscmd5151+5252+5353+hsmode=[n]5454+hscmd5555+ These commands are used to enable host sleep or wake up firmware5656+5757+ where the option is:5858+ 1 -- Enable host sleep5959+ 0 -- Wake up firmware6060+6161+ Usage:6262+ # Enable host sleep6363+ echo 1 > /debug/btmrvl/config/hsmode6464+ echo 1 > /debug/btmrvl/config/hscmd6565+6666+ # Wake up firmware6767+ echo 0 > /debug/btmrvl/config/hsmode6868+ echo 1 > /debug/btmrvl/config/hscmd6969+7070+7171+======================7272+Get driver status:7373+7474+Path: /debug/btmrvl/status/7575+7676+Usage:7777+ cat /debug/btmrvl/status/<args>7878+7979+where the args are:8080+8181+curpsmode8282+ This command displays current auto sleep status.8383+8484+psstate8585+ This command display the power save state.8686+8787+hsstate8888+ This command display the host sleep state.8989+9090+txdnldrdy9191+ This command displays the value of Tx download ready flag.9292+9393+9494+=====================9595+9696+Use hcitool to issue raw hci command, refer to hcitool manual9797+9898+ Usage: Hcitool cmd <ogf> <ocf> [Parameters]9999+100100+ Interface Control Command101101+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface102102+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface103103+ hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface104104+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface105105+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface106106+ hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface107107+108108+=======================================================================109109+110110+111111+SD8688 firmware:112112+113113+/lib/firmware/sd8688_helper.bin114114+/lib/firmware/sd8688.bin115115+116116+117117+The images can be downloaded from:118118+119119+git.infradead.org/users/dwmw2/linux-firmware.git/libertas/
+25
drivers/bluetooth/Kconfig
···170170 Say Y here to compile support for virtual HCI devices into the171171 kernel or say M to compile it as module (hci_vhci).172172173173+config BT_MRVL174174+ tristate "Marvell Bluetooth driver support"175175+ help176176+ The core driver to support Marvell Bluetooth devices.177177+178178+ This driver is required if you want to support179179+ Marvell Bluetooth devices, such as 8688.180180+181181+ Say Y here to compile Marvell Bluetooth driver182182+ into the kernel or say M to compile it as module.183183+184184+config BT_MRVL_SDIO185185+ tristate "Marvell BT-over-SDIO driver"186186+ depends on BT_MRVL && MMC187187+ select FW_LOADER188188+ help189189+ The driver for Marvell Bluetooth chipsets with SDIO interface.190190+191191+ This driver is required if you want to use Marvell Bluetooth192192+ devices with SDIO interface. Currently only SD8688 chipset is193193+ supported.194194+195195+ Say Y here to compile support for Marvell BT-over-SDIO driver196196+ into the kernel or say M to compile it as module.197197+173198endmenu174199
···11+/*22+ * Marvell Bluetooth driver: global definitions & declarations33+ *44+ * Copyright (C) 2009, Marvell International Ltd.55+ *66+ * This software file (the "File") is distributed by Marvell International77+ * Ltd. under the terms of the GNU General Public License Version 2, June 199188+ * (the "License"). You may use, redistribute and/or modify this File in99+ * accordance with the terms and conditions of the License, a copy of which1010+ * is available by writing to the Free Software Foundation, Inc.,1111+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the1212+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.1313+ *1414+ *1515+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE1616+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE1717+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about1818+ * this warranty disclaimer.1919+ *2020+ */2121+2222+#include <linux/kthread.h>2323+#include <linux/bitops.h>2424+#include <net/bluetooth/bluetooth.h>2525+2626+#define BTM_HEADER_LEN 42727+#define BTM_UPLD_SIZE 23122828+2929+/* Time to wait until Host Sleep state change in millisecond */3030+#define WAIT_UNTIL_HS_STATE_CHANGED 50003131+/* Time to wait for command response in millisecond */3232+#define WAIT_UNTIL_CMD_RESP 50003333+3434+struct btmrvl_thread {3535+ struct task_struct *task;3636+ wait_queue_head_t wait_q;3737+ void *priv;3838+};3939+4040+struct btmrvl_device {4141+ void *card;4242+ struct hci_dev *hcidev;4343+4444+ u8 tx_dnld_rdy;4545+4646+ u8 psmode;4747+ u8 pscmd;4848+ u8 hsmode;4949+ u8 hscmd;5050+5151+ /* Low byte is gap, high byte is GPIO */5252+ u16 gpio_gap;5353+5454+ u8 hscfgcmd;5555+ u8 sendcmdflag;5656+};5757+5858+struct btmrvl_adapter {5959+ u32 int_count;6060+ struct sk_buff_head tx_queue;6161+ u8 psmode;6262+ u8 ps_state;6363+ u8 hs_state;6464+ u8 wakeup_tries;6565+ wait_queue_head_t cmd_wait_q;6666+ u8 cmd_complete;6767+};6868+6969+struct btmrvl_private {7070+ struct btmrvl_device btmrvl_dev;7171+ struct btmrvl_adapter *adapter;7272+ struct btmrvl_thread main_thread;7373+ int (*hw_host_to_card) (struct btmrvl_private *priv,7474+ u8 *payload, u16 nb);7575+ int (*hw_wakeup_firmware) (struct btmrvl_private *priv);7676+ spinlock_t driver_lock; /* spinlock used by driver */7777+#ifdef CONFIG_DEBUG_FS7878+ void *debugfs_data;7979+#endif8080+};8181+8282+#define MRVL_VENDOR_PKT 0xFE8383+8484+/* Bluetooth commands */8585+#define BT_CMD_AUTO_SLEEP_MODE 0x238686+#define BT_CMD_HOST_SLEEP_CONFIG 0x598787+#define BT_CMD_HOST_SLEEP_ENABLE 0x5A8888+#define BT_CMD_MODULE_CFG_REQ 0x5B8989+9090+/* Sub-commands: Module Bringup/Shutdown Request */9191+#define MODULE_BRINGUP_REQ 0xF19292+#define MODULE_SHUTDOWN_REQ 0xF29393+9494+#define BT_EVENT_POWER_STATE 0x209595+9696+/* Bluetooth Power States */9797+#define BT_PS_ENABLE 0x029898+#define BT_PS_DISABLE 0x039999+#define BT_PS_SLEEP 0x01100100+101101+#define OGF 0x3F102102+103103+/* Host Sleep states */104104+#define HS_ACTIVATED 0x01105105+#define HS_DEACTIVATED 0x00106106+107107+/* Power Save modes */108108+#define PS_SLEEP 0x01109109+#define PS_AWAKE 0x00110110+111111+struct btmrvl_cmd {112112+ __le16 ocf_ogf;113113+ u8 length;114114+ u8 data[4];115115+} __attribute__ ((packed));116116+117117+struct btmrvl_event {118118+ u8 ec; /* event counter */119119+ u8 length;120120+ u8 data[4];121121+} __attribute__ ((packed));122122+123123+/* Prototype of global function */124124+125125+struct btmrvl_private *btmrvl_add_card(void *card);126126+int btmrvl_remove_card(struct btmrvl_private *priv);127127+128128+void btmrvl_interrupt(struct btmrvl_private *priv);129129+130130+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);131131+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);132132+133133+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);134134+int btmrvl_prepare_command(struct btmrvl_private *priv);135135+136136+#ifdef CONFIG_DEBUG_FS137137+void btmrvl_debugfs_init(struct hci_dev *hdev);138138+void btmrvl_debugfs_remove(struct hci_dev *hdev);139139+#endif
+624
drivers/bluetooth/btmrvl_main.c
···11+/**22+ * Marvell Bluetooth driver33+ *44+ * Copyright (C) 2009, Marvell International Ltd.55+ *66+ * This software file (the "File") is distributed by Marvell International77+ * Ltd. under the terms of the GNU General Public License Version 2, June 199188+ * (the "License"). You may use, redistribute and/or modify this File in99+ * accordance with the terms and conditions of the License, a copy of which1010+ * is available by writing to the Free Software Foundation, Inc.,1111+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the1212+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.1313+ *1414+ *1515+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE1616+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE1717+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about1818+ * this warranty disclaimer.1919+ **/2020+2121+#include <net/bluetooth/bluetooth.h>2222+#include <net/bluetooth/hci_core.h>2323+2424+#include "btmrvl_drv.h"2525+2626+#define VERSION "1.0"2727+2828+/*2929+ * This function is called by interface specific interrupt handler.3030+ * It updates Power Save & Host Sleep states, and wakes up the main3131+ * thread.3232+ */3333+void btmrvl_interrupt(struct btmrvl_private *priv)3434+{3535+ priv->adapter->ps_state = PS_AWAKE;3636+3737+ priv->adapter->wakeup_tries = 0;3838+3939+ priv->adapter->int_count++;4040+4141+ wake_up_interruptible(&priv->main_thread.wait_q);4242+}4343+EXPORT_SYMBOL_GPL(btmrvl_interrupt);4444+4545+void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb)4646+{4747+ struct hci_event_hdr *hdr = (void *) skb->data;4848+ struct hci_ev_cmd_complete *ec;4949+ u16 opcode, ocf;5050+5151+ if (hdr->evt == HCI_EV_CMD_COMPLETE) {5252+ ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE);5353+ opcode = __le16_to_cpu(ec->opcode);5454+ ocf = hci_opcode_ocf(opcode);5555+ if (ocf == BT_CMD_MODULE_CFG_REQ &&5656+ priv->btmrvl_dev.sendcmdflag) {5757+ priv->btmrvl_dev.sendcmdflag = false;5858+ priv->adapter->cmd_complete = true;5959+ wake_up_interruptible(&priv->adapter->cmd_wait_q);6060+ }6161+ }6262+}6363+EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt);6464+6565+int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)6666+{6767+ struct btmrvl_adapter *adapter = priv->adapter;6868+ struct btmrvl_event *event;6969+ u8 ret = 0;7070+7171+ event = (struct btmrvl_event *) skb->data;7272+ if (event->ec != 0xff) {7373+ BT_DBG("Not Marvell Event=%x", event->ec);7474+ ret = -EINVAL;7575+ goto exit;7676+ }7777+7878+ switch (event->data[0]) {7979+ case BT_CMD_AUTO_SLEEP_MODE:8080+ if (!event->data[2]) {8181+ if (event->data[1] == BT_PS_ENABLE)8282+ adapter->psmode = 1;8383+ else8484+ adapter->psmode = 0;8585+ BT_DBG("PS Mode:%s",8686+ (adapter->psmode) ? "Enable" : "Disable");8787+ } else {8888+ BT_DBG("PS Mode command failed");8989+ }9090+ break;9191+9292+ case BT_CMD_HOST_SLEEP_CONFIG:9393+ if (!event->data[3])9494+ BT_DBG("gpio=%x, gap=%x", event->data[1],9595+ event->data[2]);9696+ else9797+ BT_DBG("HSCFG command failed");9898+ break;9999+100100+ case BT_CMD_HOST_SLEEP_ENABLE:101101+ if (!event->data[1]) {102102+ adapter->hs_state = HS_ACTIVATED;103103+ if (adapter->psmode)104104+ adapter->ps_state = PS_SLEEP;105105+ wake_up_interruptible(&adapter->cmd_wait_q);106106+ BT_DBG("HS ACTIVATED!");107107+ } else {108108+ BT_DBG("HS Enable failed");109109+ }110110+ break;111111+112112+ case BT_CMD_MODULE_CFG_REQ:113113+ if (priv->btmrvl_dev.sendcmdflag &&114114+ event->data[1] == MODULE_BRINGUP_REQ) {115115+ BT_DBG("EVENT:%s", (event->data[2]) ?116116+ "Bring-up failed" : "Bring-up succeed");117117+ } else if (priv->btmrvl_dev.sendcmdflag &&118118+ event->data[1] == MODULE_SHUTDOWN_REQ) {119119+ BT_DBG("EVENT:%s", (event->data[2]) ?120120+ "Shutdown failed" : "Shutdown succeed");121121+ } else {122122+ BT_DBG("BT_CMD_MODULE_CFG_REQ resp for APP");123123+ ret = -EINVAL;124124+ }125125+ break;126126+127127+ case BT_EVENT_POWER_STATE:128128+ if (event->data[1] == BT_PS_SLEEP)129129+ adapter->ps_state = PS_SLEEP;130130+ BT_DBG("EVENT:%s",131131+ (adapter->ps_state) ? "PS_SLEEP" : "PS_AWAKE");132132+ break;133133+134134+ default:135135+ BT_DBG("Unknown Event=%d", event->data[0]);136136+ ret = -EINVAL;137137+ break;138138+ }139139+140140+exit:141141+ if (!ret)142142+ kfree_skb(skb);143143+144144+ return ret;145145+}146146+EXPORT_SYMBOL_GPL(btmrvl_process_event);147147+148148+int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)149149+{150150+ struct sk_buff *skb;151151+ struct btmrvl_cmd *cmd;152152+ int ret = 0;153153+154154+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);155155+ if (skb == NULL) {156156+ BT_ERR("No free skb");157157+ return -ENOMEM;158158+ }159159+160160+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));161161+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_MODULE_CFG_REQ));162162+ cmd->length = 1;163163+ cmd->data[0] = subcmd;164164+165165+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;166166+167167+ skb->dev = (void *) priv->btmrvl_dev.hcidev;168168+ skb_queue_head(&priv->adapter->tx_queue, skb);169169+170170+ priv->btmrvl_dev.sendcmdflag = true;171171+172172+ priv->adapter->cmd_complete = false;173173+174174+ BT_DBG("Queue module cfg Command");175175+176176+ wake_up_interruptible(&priv->main_thread.wait_q);177177+178178+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,179179+ priv->adapter->cmd_complete,180180+ msecs_to_jiffies(WAIT_UNTIL_CMD_RESP))) {181181+ ret = -ETIMEDOUT;182182+ BT_ERR("module_cfg_cmd(%x): timeout: %d",183183+ subcmd, priv->btmrvl_dev.sendcmdflag);184184+ }185185+186186+ BT_DBG("module cfg Command done");187187+188188+ return ret;189189+}190190+EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);191191+192192+static int btmrvl_enable_hs(struct btmrvl_private *priv)193193+{194194+ struct sk_buff *skb;195195+ struct btmrvl_cmd *cmd;196196+ int ret = 0;197197+198198+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);199199+ if (skb == NULL) {200200+ BT_ERR("No free skb");201201+ return -ENOMEM;202202+ }203203+204204+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));205205+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_ENABLE));206206+ cmd->length = 0;207207+208208+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;209209+210210+ skb->dev = (void *) priv->btmrvl_dev.hcidev;211211+ skb_queue_head(&priv->adapter->tx_queue, skb);212212+213213+ BT_DBG("Queue hs enable Command");214214+215215+ wake_up_interruptible(&priv->main_thread.wait_q);216216+217217+ if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,218218+ priv->adapter->hs_state,219219+ msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED))) {220220+ ret = -ETIMEDOUT;221221+ BT_ERR("timeout: %d, %d,%d", priv->adapter->hs_state,222222+ priv->adapter->ps_state,223223+ priv->adapter->wakeup_tries);224224+ }225225+226226+ return ret;227227+}228228+229229+int btmrvl_prepare_command(struct btmrvl_private *priv)230230+{231231+ struct sk_buff *skb = NULL;232232+ struct btmrvl_cmd *cmd;233233+ int ret = 0;234234+235235+ if (priv->btmrvl_dev.hscfgcmd) {236236+ priv->btmrvl_dev.hscfgcmd = 0;237237+238238+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);239239+ if (skb == NULL) {240240+ BT_ERR("No free skb");241241+ return -ENOMEM;242242+ }243243+244244+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));245245+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));246246+ cmd->length = 2;247247+ cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;248248+ cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);249249+250250+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;251251+252252+ skb->dev = (void *) priv->btmrvl_dev.hcidev;253253+ skb_queue_head(&priv->adapter->tx_queue, skb);254254+255255+ BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",256256+ cmd->data[0], cmd->data[1]);257257+ }258258+259259+ if (priv->btmrvl_dev.pscmd) {260260+ priv->btmrvl_dev.pscmd = 0;261261+262262+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);263263+ if (skb == NULL) {264264+ BT_ERR("No free skb");265265+ return -ENOMEM;266266+ }267267+268268+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));269269+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_AUTO_SLEEP_MODE));270270+ cmd->length = 1;271271+272272+ if (priv->btmrvl_dev.psmode)273273+ cmd->data[0] = BT_PS_ENABLE;274274+ else275275+ cmd->data[0] = BT_PS_DISABLE;276276+277277+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;278278+279279+ skb->dev = (void *) priv->btmrvl_dev.hcidev;280280+ skb_queue_head(&priv->adapter->tx_queue, skb);281281+282282+ BT_DBG("Queue PSMODE Command:%d", cmd->data[0]);283283+ }284284+285285+ if (priv->btmrvl_dev.hscmd) {286286+ priv->btmrvl_dev.hscmd = 0;287287+288288+ if (priv->btmrvl_dev.hsmode) {289289+ ret = btmrvl_enable_hs(priv);290290+ } else {291291+ ret = priv->hw_wakeup_firmware(priv);292292+ priv->adapter->hs_state = HS_DEACTIVATED;293293+ }294294+ }295295+296296+ return ret;297297+}298298+299299+static int btmrvl_tx_pkt(struct btmrvl_private *priv, struct sk_buff *skb)300300+{301301+ int ret = 0;302302+303303+ if (!skb || !skb->data)304304+ return -EINVAL;305305+306306+ if (!skb->len || ((skb->len + BTM_HEADER_LEN) > BTM_UPLD_SIZE)) {307307+ BT_ERR("Tx Error: Bad skb length %d : %d",308308+ skb->len, BTM_UPLD_SIZE);309309+ return -EINVAL;310310+ }311311+312312+ if (skb_headroom(skb) < BTM_HEADER_LEN) {313313+ struct sk_buff *tmp = skb;314314+315315+ skb = skb_realloc_headroom(skb, BTM_HEADER_LEN);316316+ if (!skb) {317317+ BT_ERR("Tx Error: realloc_headroom failed %d",318318+ BTM_HEADER_LEN);319319+ skb = tmp;320320+ return -EINVAL;321321+ }322322+323323+ kfree_skb(tmp);324324+ }325325+326326+ skb_push(skb, BTM_HEADER_LEN);327327+328328+ /* header type: byte[3]329329+ * HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor330330+ * header length: byte[2][1][0]331331+ */332332+333333+ skb->data[0] = (skb->len & 0x0000ff);334334+ skb->data[1] = (skb->len & 0x00ff00) >> 8;335335+ skb->data[2] = (skb->len & 0xff0000) >> 16;336336+ skb->data[3] = bt_cb(skb)->pkt_type;337337+338338+ if (priv->hw_host_to_card)339339+ ret = priv->hw_host_to_card(priv, skb->data, skb->len);340340+341341+ return ret;342342+}343343+344344+static void btmrvl_init_adapter(struct btmrvl_private *priv)345345+{346346+ skb_queue_head_init(&priv->adapter->tx_queue);347347+348348+ priv->adapter->ps_state = PS_AWAKE;349349+350350+ init_waitqueue_head(&priv->adapter->cmd_wait_q);351351+}352352+353353+static void btmrvl_free_adapter(struct btmrvl_private *priv)354354+{355355+ skb_queue_purge(&priv->adapter->tx_queue);356356+357357+ kfree(priv->adapter);358358+359359+ priv->adapter = NULL;360360+}361361+362362+static int btmrvl_ioctl(struct hci_dev *hdev,363363+ unsigned int cmd, unsigned long arg)364364+{365365+ return -ENOIOCTLCMD;366366+}367367+368368+static void btmrvl_destruct(struct hci_dev *hdev)369369+{370370+}371371+372372+static int btmrvl_send_frame(struct sk_buff *skb)373373+{374374+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;375375+ struct btmrvl_private *priv = NULL;376376+377377+ BT_DBG("type=%d, len=%d", skb->pkt_type, skb->len);378378+379379+ if (!hdev || !hdev->driver_data) {380380+ BT_ERR("Frame for unknown HCI device");381381+ return -ENODEV;382382+ }383383+384384+ priv = (struct btmrvl_private *) hdev->driver_data;385385+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {386386+ BT_ERR("Failed testing HCI_RUNING, flags=%lx", hdev->flags);387387+ print_hex_dump_bytes("data: ", DUMP_PREFIX_OFFSET,388388+ skb->data, skb->len);389389+ return -EBUSY;390390+ }391391+392392+ switch (bt_cb(skb)->pkt_type) {393393+ case HCI_COMMAND_PKT:394394+ hdev->stat.cmd_tx++;395395+ break;396396+397397+ case HCI_ACLDATA_PKT:398398+ hdev->stat.acl_tx++;399399+ break;400400+401401+ case HCI_SCODATA_PKT:402402+ hdev->stat.sco_tx++;403403+ break;404404+ }405405+406406+ skb_queue_tail(&priv->adapter->tx_queue, skb);407407+408408+ wake_up_interruptible(&priv->main_thread.wait_q);409409+410410+ return 0;411411+}412412+413413+static int btmrvl_flush(struct hci_dev *hdev)414414+{415415+ struct btmrvl_private *priv = hdev->driver_data;416416+417417+ skb_queue_purge(&priv->adapter->tx_queue);418418+419419+ return 0;420420+}421421+422422+static int btmrvl_close(struct hci_dev *hdev)423423+{424424+ struct btmrvl_private *priv = hdev->driver_data;425425+426426+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))427427+ return 0;428428+429429+ skb_queue_purge(&priv->adapter->tx_queue);430430+431431+ return 0;432432+}433433+434434+static int btmrvl_open(struct hci_dev *hdev)435435+{436436+ set_bit(HCI_RUNNING, &hdev->flags);437437+438438+ return 0;439439+}440440+441441+/*442442+ * This function handles the event generated by firmware, rx data443443+ * received from firmware, and tx data sent from kernel.444444+ */445445+static int btmrvl_service_main_thread(void *data)446446+{447447+ struct btmrvl_thread *thread = data;448448+ struct btmrvl_private *priv = thread->priv;449449+ struct btmrvl_adapter *adapter = priv->adapter;450450+ wait_queue_t wait;451451+ struct sk_buff *skb;452452+ ulong flags;453453+454454+ init_waitqueue_entry(&wait, current);455455+456456+ current->flags |= PF_NOFREEZE;457457+458458+ for (;;) {459459+ add_wait_queue(&thread->wait_q, &wait);460460+461461+ set_current_state(TASK_INTERRUPTIBLE);462462+463463+ if (adapter->wakeup_tries ||464464+ ((!adapter->int_count) &&465465+ (!priv->btmrvl_dev.tx_dnld_rdy ||466466+ skb_queue_empty(&adapter->tx_queue)))) {467467+ BT_DBG("main_thread is sleeping...");468468+ schedule();469469+ }470470+471471+ set_current_state(TASK_RUNNING);472472+473473+ remove_wait_queue(&thread->wait_q, &wait);474474+475475+ BT_DBG("main_thread woke up");476476+477477+ if (kthread_should_stop()) {478478+ BT_DBG("main_thread: break from main thread");479479+ break;480480+ }481481+482482+ spin_lock_irqsave(&priv->driver_lock, flags);483483+ if (adapter->int_count) {484484+ adapter->int_count = 0;485485+ } else if (adapter->ps_state == PS_SLEEP &&486486+ !skb_queue_empty(&adapter->tx_queue)) {487487+ spin_unlock_irqrestore(&priv->driver_lock, flags);488488+ adapter->wakeup_tries++;489489+ priv->hw_wakeup_firmware(priv);490490+ continue;491491+ }492492+ spin_unlock_irqrestore(&priv->driver_lock, flags);493493+494494+ if (adapter->ps_state == PS_SLEEP)495495+ continue;496496+497497+ if (!priv->btmrvl_dev.tx_dnld_rdy)498498+ continue;499499+500500+ skb = skb_dequeue(&adapter->tx_queue);501501+ if (skb) {502502+ if (btmrvl_tx_pkt(priv, skb))503503+ priv->btmrvl_dev.hcidev->stat.err_tx++;504504+ else505505+ priv->btmrvl_dev.hcidev->stat.byte_tx += skb->len;506506+507507+ kfree_skb(skb);508508+ }509509+ }510510+511511+ return 0;512512+}513513+514514+struct btmrvl_private *btmrvl_add_card(void *card)515515+{516516+ struct hci_dev *hdev = NULL;517517+ struct btmrvl_private *priv;518518+ int ret;519519+520520+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);521521+ if (!priv) {522522+ BT_ERR("Can not allocate priv");523523+ goto err_priv;524524+ }525525+526526+ priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);527527+ if (!priv->adapter) {528528+ BT_ERR("Allocate buffer for btmrvl_adapter failed!");529529+ goto err_adapter;530530+ }531531+532532+ btmrvl_init_adapter(priv);533533+534534+ hdev = hci_alloc_dev();535535+ if (!hdev) {536536+ BT_ERR("Can not allocate HCI device");537537+ goto err_hdev;538538+ }539539+540540+ BT_DBG("Starting kthread...");541541+ priv->main_thread.priv = priv;542542+ spin_lock_init(&priv->driver_lock);543543+544544+ init_waitqueue_head(&priv->main_thread.wait_q);545545+ priv->main_thread.task = kthread_run(btmrvl_service_main_thread,546546+ &priv->main_thread, "btmrvl_main_service");547547+548548+ priv->btmrvl_dev.hcidev = hdev;549549+ priv->btmrvl_dev.card = card;550550+551551+ hdev->driver_data = priv;552552+553553+ priv->btmrvl_dev.tx_dnld_rdy = true;554554+555555+ hdev->type = HCI_SDIO;556556+ hdev->open = btmrvl_open;557557+ hdev->close = btmrvl_close;558558+ hdev->flush = btmrvl_flush;559559+ hdev->send = btmrvl_send_frame;560560+ hdev->destruct = btmrvl_destruct;561561+ hdev->ioctl = btmrvl_ioctl;562562+ hdev->owner = THIS_MODULE;563563+564564+ ret = hci_register_dev(hdev);565565+ if (ret < 0) {566566+ BT_ERR("Can not register HCI device");567567+ goto err_hci_register_dev;568568+ }569569+570570+#ifdef CONFIG_DEBUG_FS571571+ btmrvl_debugfs_init(hdev);572572+#endif573573+574574+ return priv;575575+576576+err_hci_register_dev:577577+ /* Stop the thread servicing the interrupts */578578+ kthread_stop(priv->main_thread.task);579579+580580+ hci_free_dev(hdev);581581+582582+err_hdev:583583+ btmrvl_free_adapter(priv);584584+585585+err_adapter:586586+ kfree(priv);587587+588588+err_priv:589589+ return NULL;590590+}591591+EXPORT_SYMBOL_GPL(btmrvl_add_card);592592+593593+int btmrvl_remove_card(struct btmrvl_private *priv)594594+{595595+ struct hci_dev *hdev;596596+597597+ hdev = priv->btmrvl_dev.hcidev;598598+599599+ wake_up_interruptible(&priv->adapter->cmd_wait_q);600600+601601+ kthread_stop(priv->main_thread.task);602602+603603+#ifdef CONFIG_DEBUG_FS604604+ btmrvl_debugfs_remove(hdev);605605+#endif606606+607607+ hci_unregister_dev(hdev);608608+609609+ hci_free_dev(hdev);610610+611611+ priv->btmrvl_dev.hcidev = NULL;612612+613613+ btmrvl_free_adapter(priv);614614+615615+ kfree(priv);616616+617617+ return 0;618618+}619619+EXPORT_SYMBOL_GPL(btmrvl_remove_card);620620+621621+MODULE_AUTHOR("Marvell International Ltd.");622622+MODULE_DESCRIPTION("Marvell Bluetooth driver ver " VERSION);623623+MODULE_VERSION(VERSION);624624+MODULE_LICENSE("GPL v2");
+1003
drivers/bluetooth/btmrvl_sdio.c
···11+/**22+ * Marvell BT-over-SDIO driver: SDIO interface related functions.33+ *44+ * Copyright (C) 2009, Marvell International Ltd.55+ *66+ * This software file (the "File") is distributed by Marvell International77+ * Ltd. under the terms of the GNU General Public License Version 2, June 199188+ * (the "License"). You may use, redistribute and/or modify this File in99+ * accordance with the terms and conditions of the License, a copy of which1010+ * is available by writing to the Free Software Foundation, Inc.,1111+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the1212+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.1313+ *1414+ *1515+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE1616+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE1717+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about1818+ * this warranty disclaimer.1919+ **/2020+2121+#include <linux/firmware.h>2222+2323+#include <linux/mmc/sdio_ids.h>2424+#include <linux/mmc/sdio_func.h>2525+2626+#include <net/bluetooth/bluetooth.h>2727+#include <net/bluetooth/hci_core.h>2828+2929+#include "btmrvl_drv.h"3030+#include "btmrvl_sdio.h"3131+3232+#define VERSION "1.0"3333+3434+/* The btmrvl_sdio_remove() callback function is called3535+ * when user removes this module from kernel space or ejects3636+ * the card from the slot. The driver handles these 2 cases3737+ * differently.3838+ * If the user is removing the module, a MODULE_SHUTDOWN_REQ3939+ * command is sent to firmware and interrupt will be disabled.4040+ * If the card is removed, there is no need to send command4141+ * or disable interrupt.4242+ *4343+ * The variable 'user_rmmod' is used to distinguish these two4444+ * scenarios. This flag is initialized as FALSE in case the card4545+ * is removed, and will be set to TRUE for module removal when4646+ * module_exit function is called.4747+ */4848+static u8 user_rmmod;4949+5050+static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {5151+ .helper = "sd8688_helper.bin",5252+ .firmware = "sd8688.bin",5353+};5454+5555+static const struct sdio_device_id btmrvl_sdio_ids[] = {5656+ /* Marvell SD8688 Bluetooth device */5757+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),5858+ .driver_data = (unsigned long) &btmrvl_sdio_sd6888 },5959+6060+ { } /* Terminating entry */6161+};6262+6363+MODULE_DEVICE_TABLE(sdio, btmrvl_sdio_ids);6464+6565+static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)6666+{6767+ u8 reg;6868+ int ret;6969+7070+ reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);7171+ if (!ret)7272+ card->rx_unit = reg;7373+7474+ return ret;7575+}7676+7777+static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)7878+{7979+ u8 fws0, fws1;8080+ int ret;8181+8282+ *dat = 0;8383+8484+ fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret);8585+8686+ if (!ret)8787+ fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);8888+8989+ if (ret)9090+ return -EIO;9191+9292+ *dat = (((u16) fws1) << 8) | fws0;9393+9494+ return 0;9595+}9696+9797+static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)9898+{9999+ u8 reg;100100+ int ret;101101+102102+ reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);103103+ if (!ret)104104+ *dat = (u16) reg << card->rx_unit;105105+106106+ return ret;107107+}108108+109109+static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,110110+ u8 mask)111111+{112112+ int ret;113113+114114+ sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);115115+ if (ret) {116116+ BT_ERR("Unable to enable the host interrupt!");117117+ ret = -EIO;118118+ }119119+120120+ return ret;121121+}122122+123123+static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,124124+ u8 mask)125125+{126126+ u8 host_int_mask;127127+ int ret;128128+129129+ host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);130130+ if (ret)131131+ return -EIO;132132+133133+ host_int_mask &= ~mask;134134+135135+ sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);136136+ if (ret < 0) {137137+ BT_ERR("Unable to disable the host interrupt!");138138+ return -EIO;139139+ }140140+141141+ return 0;142142+}143143+144144+static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)145145+{146146+ unsigned int tries;147147+ u8 status;148148+ int ret;149149+150150+ for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {151151+ status = sdio_readb(card->func, CARD_STATUS_REG, &ret);152152+ if (ret)153153+ goto failed;154154+ if ((status & bits) == bits)155155+ return ret;156156+157157+ udelay(1);158158+ }159159+160160+ ret = -ETIMEDOUT;161161+162162+failed:163163+ BT_ERR("FAILED! ret=%d", ret);164164+165165+ return ret;166166+}167167+168168+static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,169169+ int pollnum)170170+{171171+ int ret = -ETIMEDOUT;172172+ u16 firmwarestat;173173+ unsigned int tries;174174+175175+ /* Wait for firmware to become ready */176176+ for (tries = 0; tries < pollnum; tries++) {177177+ if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0)178178+ continue;179179+180180+ if (firmwarestat == FIRMWARE_READY) {181181+ ret = 0;182182+ break;183183+ } else {184184+ msleep(10);185185+ }186186+ }187187+188188+ return ret;189189+}190190+191191+static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)192192+{193193+ const struct firmware *fw_helper = NULL;194194+ const u8 *helper = NULL;195195+ int ret;196196+ void *tmphlprbuf = NULL;197197+ int tmphlprbufsz, hlprblknow, helperlen;198198+ u8 *helperbuf;199199+ u32 tx_len;200200+201201+ ret = request_firmware(&fw_helper, card->helper,202202+ &card->func->dev);203203+ if ((ret < 0) || !fw_helper) {204204+ BT_ERR("request_firmware(helper) failed, error code = %d",205205+ ret);206206+ ret = -ENOENT;207207+ goto done;208208+ }209209+210210+ helper = fw_helper->data;211211+ helperlen = fw_helper->size;212212+213213+ BT_DBG("Downloading helper image (%d bytes), block size %d bytes",214214+ helperlen, SDIO_BLOCK_SIZE);215215+216216+ tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);217217+218218+ tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL);219219+ if (!tmphlprbuf) {220220+ BT_ERR("Unable to allocate buffer for helper."221221+ " Terminating download");222222+ ret = -ENOMEM;223223+ goto done;224224+ }225225+226226+ memset(tmphlprbuf, 0, tmphlprbufsz);227227+228228+ helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);229229+230230+ /* Perform helper data transfer */231231+ tx_len = (FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE)232232+ - SDIO_HEADER_LEN;233233+ hlprblknow = 0;234234+235235+ do {236236+ ret = btmrvl_sdio_poll_card_status(card,237237+ CARD_IO_READY | DN_LD_CARD_RDY);238238+ if (ret < 0) {239239+ BT_ERR("Helper download poll status timeout @ %d",240240+ hlprblknow);241241+ goto done;242242+ }243243+244244+ /* Check if there is more data? */245245+ if (hlprblknow >= helperlen)246246+ break;247247+248248+ if (helperlen - hlprblknow < tx_len)249249+ tx_len = helperlen - hlprblknow;250250+251251+ /* Little-endian */252252+ helperbuf[0] = ((tx_len & 0x000000ff) >> 0);253253+ helperbuf[1] = ((tx_len & 0x0000ff00) >> 8);254254+ helperbuf[2] = ((tx_len & 0x00ff0000) >> 16);255255+ helperbuf[3] = ((tx_len & 0xff000000) >> 24);256256+257257+ memcpy(&helperbuf[SDIO_HEADER_LEN], &helper[hlprblknow],258258+ tx_len);259259+260260+ /* Now send the data */261261+ ret = sdio_writesb(card->func, card->ioport, helperbuf,262262+ FIRMWARE_TRANSFER_NBLOCK * SDIO_BLOCK_SIZE);263263+ if (ret < 0) {264264+ BT_ERR("IO error during helper download @ %d",265265+ hlprblknow);266266+ goto done;267267+ }268268+269269+ hlprblknow += tx_len;270270+ } while (true);271271+272272+ BT_DBG("Transferring helper image EOF block");273273+274274+ memset(helperbuf, 0x0, SDIO_BLOCK_SIZE);275275+276276+ ret = sdio_writesb(card->func, card->ioport, helperbuf,277277+ SDIO_BLOCK_SIZE);278278+ if (ret < 0) {279279+ BT_ERR("IO error in writing helper image EOF block");280280+ goto done;281281+ }282282+283283+ ret = 0;284284+285285+done:286286+ kfree(tmphlprbuf);287287+ if (fw_helper)288288+ release_firmware(fw_helper);289289+290290+ return ret;291291+}292292+293293+static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)294294+{295295+ const struct firmware *fw_firmware = NULL;296296+ const u8 *firmware = NULL;297297+ int firmwarelen, tmpfwbufsz, ret;298298+ unsigned int tries, offset;299299+ u8 base0, base1;300300+ void *tmpfwbuf = NULL;301301+ u8 *fwbuf;302302+ u16 len;303303+ int txlen = 0, tx_blocks = 0, count = 0;304304+305305+ ret = request_firmware(&fw_firmware, card->firmware,306306+ &card->func->dev);307307+ if ((ret < 0) || !fw_firmware) {308308+ BT_ERR("request_firmware(firmware) failed, error code = %d",309309+ ret);310310+ ret = -ENOENT;311311+ goto done;312312+ }313313+314314+ firmware = fw_firmware->data;315315+ firmwarelen = fw_firmware->size;316316+317317+ BT_DBG("Downloading FW image (%d bytes)", firmwarelen);318318+319319+ tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN);320320+ tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL);321321+ if (!tmpfwbuf) {322322+ BT_ERR("Unable to allocate buffer for firmware."323323+ " Terminating download");324324+ ret = -ENOMEM;325325+ goto done;326326+ }327327+328328+ memset(tmpfwbuf, 0, tmpfwbufsz);329329+330330+ /* Ensure aligned firmware buffer */331331+ fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN);332332+333333+ /* Perform firmware data transfer */334334+ offset = 0;335335+ do {336336+ ret = btmrvl_sdio_poll_card_status(card,337337+ CARD_IO_READY | DN_LD_CARD_RDY);338338+ if (ret < 0) {339339+ BT_ERR("FW download with helper poll status"340340+ " timeout @ %d", offset);341341+ goto done;342342+ }343343+344344+ /* Check if there is more data ? */345345+ if (offset >= firmwarelen)346346+ break;347347+348348+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {349349+ base0 = sdio_readb(card->func,350350+ SQ_READ_BASE_ADDRESS_A0_REG, &ret);351351+ if (ret) {352352+ BT_ERR("BASE0 register read failed:"353353+ " base0 = 0x%04X(%d)."354354+ " Terminating download",355355+ base0, base0);356356+ ret = -EIO;357357+ goto done;358358+ }359359+ base1 = sdio_readb(card->func,360360+ SQ_READ_BASE_ADDRESS_A1_REG, &ret);361361+ if (ret) {362362+ BT_ERR("BASE1 register read failed:"363363+ " base1 = 0x%04X(%d)."364364+ " Terminating download",365365+ base1, base1);366366+ ret = -EIO;367367+ goto done;368368+ }369369+370370+ len = (((u16) base1) << 8) | base0;371371+ if (len)372372+ break;373373+374374+ udelay(10);375375+ }376376+377377+ if (!len)378378+ break;379379+ else if (len > BTM_UPLD_SIZE) {380380+ BT_ERR("FW download failure @%d, invalid length %d",381381+ offset, len);382382+ ret = -EINVAL;383383+ goto done;384384+ }385385+386386+ txlen = len;387387+388388+ if (len & BIT(0)) {389389+ count++;390390+ if (count > MAX_WRITE_IOMEM_RETRY) {391391+ BT_ERR("FW download failure @%d, "392392+ "over max retry count", offset);393393+ ret = -EIO;394394+ goto done;395395+ }396396+ BT_ERR("FW CRC error indicated by the helper: "397397+ "len = 0x%04X, txlen = %d", len, txlen);398398+ len &= ~BIT(0);399399+ /* Set txlen to 0 so as to resend from same offset */400400+ txlen = 0;401401+ } else {402402+ count = 0;403403+404404+ /* Last block ? */405405+ if (firmwarelen - offset < txlen)406406+ txlen = firmwarelen - offset;407407+408408+ tx_blocks =409409+ (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;410410+411411+ memcpy(fwbuf, &firmware[offset], txlen);412412+ }413413+414414+ ret = sdio_writesb(card->func, card->ioport, fwbuf,415415+ tx_blocks * SDIO_BLOCK_SIZE);416416+417417+ if (ret < 0) {418418+ BT_ERR("FW download, writesb(%d) failed @%d",419419+ count, offset);420420+ sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,421421+ &ret);422422+ if (ret)423423+ BT_ERR("writeb failed (CFG)");424424+ }425425+426426+ offset += txlen;427427+ } while (true);428428+429429+ BT_DBG("FW download over, size %d bytes", offset);430430+431431+ ret = 0;432432+433433+done:434434+ kfree(tmpfwbuf);435435+436436+ if (fw_firmware)437437+ release_firmware(fw_firmware);438438+439439+ return ret;440440+}441441+442442+static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)443443+{444444+ u16 buf_len = 0;445445+ int ret, buf_block_len, blksz;446446+ struct sk_buff *skb = NULL;447447+ u32 type;448448+ u8 *payload = NULL;449449+ struct hci_dev *hdev = priv->btmrvl_dev.hcidev;450450+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;451451+452452+ if (!card || !card->func) {453453+ BT_ERR("card or function is NULL!");454454+ ret = -EINVAL;455455+ goto exit;456456+ }457457+458458+ /* Read the length of data to be transferred */459459+ ret = btmrvl_sdio_read_rx_len(card, &buf_len);460460+ if (ret < 0) {461461+ BT_ERR("read rx_len failed");462462+ ret = -EIO;463463+ goto exit;464464+ }465465+466466+ blksz = SDIO_BLOCK_SIZE;467467+ buf_block_len = (buf_len + blksz - 1) / blksz;468468+469469+ if (buf_len <= SDIO_HEADER_LEN470470+ || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {471471+ BT_ERR("invalid packet length: %d", buf_len);472472+ ret = -EINVAL;473473+ goto exit;474474+ }475475+476476+ /* Allocate buffer */477477+ skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN,478478+ GFP_ATOMIC);479479+ if (skb == NULL) {480480+ BT_ERR("No free skb");481481+ goto exit;482482+ }483483+484484+ if ((unsigned long) skb->data & (BTSDIO_DMA_ALIGN - 1)) {485485+ skb_put(skb, (unsigned long) skb->data &486486+ (BTSDIO_DMA_ALIGN - 1));487487+ skb_pull(skb, (unsigned long) skb->data &488488+ (BTSDIO_DMA_ALIGN - 1));489489+ }490490+491491+ payload = skb->data;492492+493493+ ret = sdio_readsb(card->func, payload, card->ioport,494494+ buf_block_len * blksz);495495+ if (ret < 0) {496496+ BT_ERR("readsb failed: %d", ret);497497+ ret = -EIO;498498+ goto exit;499499+ }500500+501501+ /* This is SDIO specific header length: byte[2][1][0], type: byte[3]502502+ * (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor)503503+ */504504+505505+ buf_len = payload[0];506506+ buf_len |= (u16) payload[1] << 8;507507+ type = payload[3];508508+509509+ switch (type) {510510+ case HCI_ACLDATA_PKT:511511+ case HCI_SCODATA_PKT:512512+ case HCI_EVENT_PKT:513513+ bt_cb(skb)->pkt_type = type;514514+ skb->dev = (void *)hdev;515515+ skb_put(skb, buf_len);516516+ skb_pull(skb, SDIO_HEADER_LEN);517517+518518+ if (type == HCI_EVENT_PKT)519519+ btmrvl_check_evtpkt(priv, skb);520520+521521+ hci_recv_frame(skb);522522+ hdev->stat.byte_rx += buf_len;523523+ break;524524+525525+ case MRVL_VENDOR_PKT:526526+ bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;527527+ skb->dev = (void *)hdev;528528+ skb_put(skb, buf_len);529529+ skb_pull(skb, SDIO_HEADER_LEN);530530+531531+ if (btmrvl_process_event(priv, skb))532532+ hci_recv_frame(skb);533533+534534+ hdev->stat.byte_rx += buf_len;535535+ break;536536+537537+ default:538538+ BT_ERR("Unknow packet type:%d", type);539539+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,540540+ blksz * buf_block_len);541541+542542+ kfree_skb(skb);543543+ skb = NULL;544544+ break;545545+ }546546+547547+exit:548548+ if (ret) {549549+ hdev->stat.err_rx++;550550+ if (skb)551551+ kfree_skb(skb);552552+ }553553+554554+ return ret;555555+}556556+557557+static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg)558558+{559559+ int ret;560560+ u8 sdio_ireg = 0;561561+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;562562+563563+ *ireg = 0;564564+565565+ sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);566566+ if (ret) {567567+ BT_ERR("sdio_readb: read int status register failed");568568+ ret = -EIO;569569+ goto done;570570+ }571571+572572+ if (sdio_ireg != 0) {573573+ /*574574+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS575575+ * Clear the interrupt status register and re-enable the576576+ * interrupt.577577+ */578578+ BT_DBG("sdio_ireg = 0x%x", sdio_ireg);579579+580580+ sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS |581581+ UP_LD_HOST_INT_STATUS),582582+ HOST_INTSTATUS_REG, &ret);583583+ if (ret) {584584+ BT_ERR("sdio_writeb: clear int status register "585585+ "failed");586586+ ret = -EIO;587587+ goto done;588588+ }589589+ }590590+591591+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {592592+ if (priv->btmrvl_dev.tx_dnld_rdy)593593+ BT_DBG("tx_done already received: "594594+ " int_status=0x%x", sdio_ireg);595595+ else596596+ priv->btmrvl_dev.tx_dnld_rdy = true;597597+ }598598+599599+ if (sdio_ireg & UP_LD_HOST_INT_STATUS)600600+ btmrvl_sdio_card_to_host(priv);601601+602602+ *ireg = sdio_ireg;603603+604604+ ret = 0;605605+606606+done:607607+ return ret;608608+}609609+610610+static void btmrvl_sdio_interrupt(struct sdio_func *func)611611+{612612+ struct btmrvl_private *priv;613613+ struct hci_dev *hcidev;614614+ struct btmrvl_sdio_card *card;615615+ u8 ireg = 0;616616+617617+ card = sdio_get_drvdata(func);618618+ if (card && card->priv) {619619+ priv = card->priv;620620+ hcidev = priv->btmrvl_dev.hcidev;621621+622622+ if (btmrvl_sdio_get_int_status(priv, &ireg))623623+ BT_ERR("reading HOST_INT_STATUS_REG failed");624624+ else625625+ BT_DBG("HOST_INT_STATUS_REG %#x", ireg);626626+627627+ btmrvl_interrupt(priv);628628+ }629629+}630630+631631+static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)632632+{633633+ struct sdio_func *func;634634+ u8 reg;635635+ int ret = 0;636636+637637+ if (!card || !card->func) {638638+ BT_ERR("Error: card or function is NULL!");639639+ ret = -EINVAL;640640+ goto failed;641641+ }642642+643643+ func = card->func;644644+645645+ sdio_claim_host(func);646646+647647+ ret = sdio_enable_func(func);648648+ if (ret) {649649+ BT_ERR("sdio_enable_func() failed: ret=%d", ret);650650+ ret = -EIO;651651+ goto release_host;652652+ }653653+654654+ ret = sdio_claim_irq(func, btmrvl_sdio_interrupt);655655+ if (ret) {656656+ BT_ERR("sdio_claim_irq failed: ret=%d", ret);657657+ ret = -EIO;658658+ goto disable_func;659659+ }660660+661661+ ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE);662662+ if (ret) {663663+ BT_ERR("cannot set SDIO block size");664664+ ret = -EIO;665665+ goto release_irq;666666+ }667667+668668+ reg = sdio_readb(func, IO_PORT_0_REG, &ret);669669+ if (ret < 0) {670670+ ret = -EIO;671671+ goto release_irq;672672+ }673673+674674+ card->ioport = reg;675675+676676+ reg = sdio_readb(func, IO_PORT_1_REG, &ret);677677+ if (ret < 0) {678678+ ret = -EIO;679679+ goto release_irq;680680+ }681681+682682+ card->ioport |= (reg << 8);683683+684684+ reg = sdio_readb(func, IO_PORT_2_REG, &ret);685685+ if (ret < 0) {686686+ ret = -EIO;687687+ goto release_irq;688688+ }689689+690690+ card->ioport |= (reg << 16);691691+692692+ BT_DBG("SDIO FUNC%d IO port: 0x%x", func->num, card->ioport);693693+694694+ sdio_set_drvdata(func, card);695695+696696+ sdio_release_host(func);697697+698698+ return 0;699699+700700+release_irq:701701+ sdio_release_irq(func);702702+703703+disable_func:704704+ sdio_disable_func(func);705705+706706+release_host:707707+ sdio_release_host(func);708708+709709+failed:710710+ return ret;711711+}712712+713713+static int btmrvl_sdio_unregister_dev(struct btmrvl_sdio_card *card)714714+{715715+ if (card && card->func) {716716+ sdio_claim_host(card->func);717717+ sdio_release_irq(card->func);718718+ sdio_disable_func(card->func);719719+ sdio_release_host(card->func);720720+ sdio_set_drvdata(card->func, NULL);721721+ }722722+723723+ return 0;724724+}725725+726726+static int btmrvl_sdio_enable_host_int(struct btmrvl_sdio_card *card)727727+{728728+ int ret;729729+730730+ if (!card || !card->func)731731+ return -EINVAL;732732+733733+ sdio_claim_host(card->func);734734+735735+ ret = btmrvl_sdio_enable_host_int_mask(card, HIM_ENABLE);736736+737737+ btmrvl_sdio_get_rx_unit(card);738738+739739+ sdio_release_host(card->func);740740+741741+ return ret;742742+}743743+744744+static int btmrvl_sdio_disable_host_int(struct btmrvl_sdio_card *card)745745+{746746+ int ret;747747+748748+ if (!card || !card->func)749749+ return -EINVAL;750750+751751+ sdio_claim_host(card->func);752752+753753+ ret = btmrvl_sdio_disable_host_int_mask(card, HIM_DISABLE);754754+755755+ sdio_release_host(card->func);756756+757757+ return ret;758758+}759759+760760+static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,761761+ u8 *payload, u16 nb)762762+{763763+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;764764+ int ret = 0;765765+ int buf_block_len;766766+ int blksz;767767+ int i = 0;768768+ u8 *buf = NULL;769769+ void *tmpbuf = NULL;770770+ int tmpbufsz;771771+772772+ if (!card || !card->func) {773773+ BT_ERR("card or function is NULL!");774774+ return -EINVAL;775775+ }776776+777777+ buf = payload;778778+ if ((unsigned long) payload & (BTSDIO_DMA_ALIGN - 1)) {779779+ tmpbufsz = ALIGN_SZ(nb, BTSDIO_DMA_ALIGN);780780+ tmpbuf = kzalloc(tmpbufsz, GFP_KERNEL);781781+ if (!tmpbuf)782782+ return -ENOMEM;783783+ buf = (u8 *) ALIGN_ADDR(tmpbuf, BTSDIO_DMA_ALIGN);784784+ memcpy(buf, payload, nb);785785+ }786786+787787+ blksz = SDIO_BLOCK_SIZE;788788+ buf_block_len = (nb + blksz - 1) / blksz;789789+790790+ sdio_claim_host(card->func);791791+792792+ do {793793+ /* Transfer data to card */794794+ ret = sdio_writesb(card->func, card->ioport, buf,795795+ buf_block_len * blksz);796796+ if (ret < 0) {797797+ i++;798798+ BT_ERR("i=%d writesb failed: %d", i, ret);799799+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,800800+ payload, nb);801801+ ret = -EIO;802802+ if (i > MAX_WRITE_IOMEM_RETRY)803803+ goto exit;804804+ }805805+ } while (ret);806806+807807+ priv->btmrvl_dev.tx_dnld_rdy = false;808808+809809+exit:810810+ sdio_release_host(card->func);811811+812812+ return ret;813813+}814814+815815+static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)816816+{817817+ int ret = 0;818818+819819+ if (!card || !card->func) {820820+ BT_ERR("card or function is NULL!");821821+ return -EINVAL;822822+ }823823+ sdio_claim_host(card->func);824824+825825+ if (!btmrvl_sdio_verify_fw_download(card, 1)) {826826+ BT_DBG("Firmware already downloaded!");827827+ goto done;828828+ }829829+830830+ ret = btmrvl_sdio_download_helper(card);831831+ if (ret) {832832+ BT_ERR("Failed to download helper!");833833+ ret = -EIO;834834+ goto done;835835+ }836836+837837+ if (btmrvl_sdio_download_fw_w_helper(card)) {838838+ BT_ERR("Failed to download firmware!");839839+ ret = -EIO;840840+ goto done;841841+ }842842+843843+ if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {844844+ BT_ERR("FW failed to be active in time!");845845+ ret = -ETIMEDOUT;846846+ goto done;847847+ }848848+849849+done:850850+ sdio_release_host(card->func);851851+852852+ return ret;853853+}854854+855855+static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)856856+{857857+ struct btmrvl_sdio_card *card = priv->btmrvl_dev.card;858858+ int ret = 0;859859+860860+ if (!card || !card->func) {861861+ BT_ERR("card or function is NULL!");862862+ return -EINVAL;863863+ }864864+865865+ sdio_claim_host(card->func);866866+867867+ sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);868868+869869+ sdio_release_host(card->func);870870+871871+ BT_DBG("wake up firmware");872872+873873+ return ret;874874+}875875+876876+static int btmrvl_sdio_probe(struct sdio_func *func,877877+ const struct sdio_device_id *id)878878+{879879+ int ret = 0;880880+ struct btmrvl_private *priv = NULL;881881+ struct btmrvl_sdio_card *card = NULL;882882+883883+ BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",884884+ id->vendor, id->device, id->class, func->num);885885+886886+ card = kzalloc(sizeof(*card), GFP_KERNEL);887887+ if (!card) {888888+ ret = -ENOMEM;889889+ goto done;890890+ }891891+892892+ card->func = func;893893+894894+ if (id->driver_data) {895895+ struct btmrvl_sdio_device *data = (void *) id->driver_data;896896+ card->helper = data->helper;897897+ card->firmware = data->firmware;898898+ }899899+900900+ if (btmrvl_sdio_register_dev(card) < 0) {901901+ BT_ERR("Failed to register BT device!");902902+ ret = -ENODEV;903903+ goto free_card;904904+ }905905+906906+ /* Disable the interrupts on the card */907907+ btmrvl_sdio_disable_host_int(card);908908+909909+ if (btmrvl_sdio_download_fw(card)) {910910+ BT_ERR("Downloading firmware failed!");911911+ ret = -ENODEV;912912+ goto unreg_dev;913913+ }914914+915915+ msleep(100);916916+917917+ btmrvl_sdio_enable_host_int(card);918918+919919+ priv = btmrvl_add_card(card);920920+ if (!priv) {921921+ BT_ERR("Initializing card failed!");922922+ ret = -ENODEV;923923+ goto disable_host_int;924924+ }925925+926926+ card->priv = priv;927927+928928+ /* Initialize the interface specific function pointers */929929+ priv->hw_host_to_card = btmrvl_sdio_host_to_card;930930+ priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;931931+932932+ btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);933933+934934+ return 0;935935+936936+disable_host_int:937937+ btmrvl_sdio_disable_host_int(card);938938+unreg_dev:939939+ btmrvl_sdio_unregister_dev(card);940940+free_card:941941+ kfree(card);942942+done:943943+ return ret;944944+}945945+946946+static void btmrvl_sdio_remove(struct sdio_func *func)947947+{948948+ struct btmrvl_sdio_card *card;949949+950950+ if (func) {951951+ card = sdio_get_drvdata(func);952952+ if (card) {953953+ /* Send SHUTDOWN command & disable interrupt954954+ * if user removes the module.955955+ */956956+ if (user_rmmod) {957957+ btmrvl_send_module_cfg_cmd(card->priv,958958+ MODULE_SHUTDOWN_REQ);959959+ btmrvl_sdio_disable_host_int(card);960960+ }961961+ BT_DBG("unregester dev");962962+ btmrvl_sdio_unregister_dev(card);963963+ btmrvl_remove_card(card->priv);964964+ kfree(card);965965+ }966966+ }967967+}968968+969969+static struct sdio_driver bt_mrvl_sdio = {970970+ .name = "btmrvl_sdio",971971+ .id_table = btmrvl_sdio_ids,972972+ .probe = btmrvl_sdio_probe,973973+ .remove = btmrvl_sdio_remove,974974+};975975+976976+static int btmrvl_sdio_init_module(void)977977+{978978+ if (sdio_register_driver(&bt_mrvl_sdio) != 0) {979979+ BT_ERR("SDIO Driver Registration Failed");980980+ return -ENODEV;981981+ }982982+983983+ /* Clear the flag in case user removes the card. */984984+ user_rmmod = 0;985985+986986+ return 0;987987+}988988+989989+static void btmrvl_sdio_exit_module(void)990990+{991991+ /* Set the flag as user is removing this module. */992992+ user_rmmod = 1;993993+994994+ sdio_unregister_driver(&bt_mrvl_sdio);995995+}996996+997997+module_init(btmrvl_sdio_init_module);998998+module_exit(btmrvl_sdio_exit_module);999999+10001000+MODULE_AUTHOR("Marvell International Ltd.");10011001+MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);10021002+MODULE_VERSION(VERSION);10031003+MODULE_LICENSE("GPL v2");
+108
drivers/bluetooth/btmrvl_sdio.h
···11+/**22+ * Marvell BT-over-SDIO driver: SDIO interface related definitions33+ *44+ * Copyright (C) 2009, Marvell International Ltd.55+ *66+ * This software file (the "File") is distributed by Marvell International77+ * Ltd. under the terms of the GNU General Public License Version 2, June 199188+ * (the "License"). You may use, redistribute and/or modify this File in99+ * accordance with the terms and conditions of the License, a copy of which1010+ * is available by writing to the Free Software Foundation, Inc.,1111+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the1212+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.1313+ *1414+ *1515+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE1616+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE1717+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about1818+ * this warranty disclaimer.1919+ *2020+ **/2121+2222+#define SDIO_HEADER_LEN 42323+2424+/* SD block size can not bigger than 64 due to buf size limit in firmware */2525+/* define SD block size for data Tx/Rx */2626+#define SDIO_BLOCK_SIZE 642727+2828+/* Number of blocks for firmware transfer */2929+#define FIRMWARE_TRANSFER_NBLOCK 23030+3131+/* This is for firmware specific length */3232+#define FW_EXTRA_LEN 363333+3434+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)3535+3636+#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \3737+ (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN)3838+3939+#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \4040+ MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \4141+ + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \4242+ * SDIO_BLOCK_SIZE)4343+4444+/* The number of times to try when polling for status */4545+#define MAX_POLL_TRIES 1004646+4747+/* Max retry number of CMD53 write */4848+#define MAX_WRITE_IOMEM_RETRY 24949+5050+/* Host Control Registers */5151+#define IO_PORT_0_REG 0x005252+#define IO_PORT_1_REG 0x015353+#define IO_PORT_2_REG 0x025454+5555+#define CONFIG_REG 0x035656+#define HOST_POWER_UP BIT(1)5757+#define HOST_CMD53_FIN BIT(2)5858+5959+#define HOST_INT_MASK_REG 0x046060+#define HIM_DISABLE 0xff6161+#define HIM_ENABLE (BIT(0) | BIT(1))6262+6363+#define HOST_INTSTATUS_REG 0x056464+#define UP_LD_HOST_INT_STATUS BIT(0)6565+#define DN_LD_HOST_INT_STATUS BIT(1)6666+6767+/* Card Control Registers */6868+#define SQ_READ_BASE_ADDRESS_A0_REG 0x106969+#define SQ_READ_BASE_ADDRESS_A1_REG 0x117070+7171+#define CARD_STATUS_REG 0x207272+#define DN_LD_CARD_RDY BIT(0)7373+#define CARD_IO_READY BIT(3)7474+7575+#define CARD_FW_STATUS0_REG 0x407676+#define CARD_FW_STATUS1_REG 0x417777+#define FIRMWARE_READY 0xfedc7878+7979+#define CARD_RX_LEN_REG 0x428080+#define CARD_RX_UNIT_REG 0x438181+8282+8383+struct btmrvl_sdio_card {8484+ struct sdio_func *func;8585+ u32 ioport;8686+ const char *helper;8787+ const char *firmware;8888+ u8 rx_unit;8989+ struct btmrvl_private *priv;9090+};9191+9292+struct btmrvl_sdio_device {9393+ const char *helper;9494+ const char *firmware;9595+};9696+9797+9898+/* Platform specific DMA alignment */9999+#define BTSDIO_DMA_ALIGN 8100100+101101+/* Macros for Data Alignment : size */102102+#define ALIGN_SZ(p, a) \103103+ (((p) + ((a) - 1)) & ~((a) - 1))104104+105105+/* Macros for Data Alignment : address */106106+#define ALIGN_ADDR(p, a) \107107+ ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \108108+ ~(((unsigned long)(a)) - 1))
···3434config BT_L2CAP3535 tristate "L2CAP protocol support"3636 depends on BT3737+ select CRC163738 help3839 L2CAP (Logical Link Control and Adaptation Protocol) provides3940 connection oriented and connection-less data transport. L2CAP