Loading Documentation/00-INDEX +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ block/ - info on the Block I/O (BIO) layer. blockdev/ - info on block devices & drivers btmrvl.txt - info on Marvell Bluetooth driver usage. cachetlb.txt - describes the cache/TLB flushing interfaces Linux uses. cdrom/ Loading Documentation/btmrvl.txt 0 → 100644 +119 −0 Original line number Diff line number Diff line ======================================================================= README for btmrvl driver ======================================================================= All commands are used via debugfs interface. ===================== Set/get driver configurations: Path: /debug/btmrvl/config/ gpiogap=[n] hscfgcmd These commands are used to configure the host sleep parameters. bit 8:0 -- Gap bit 16:8 -- GPIO where GPIO is the pin number of GPIO used to wake up the host. It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface wakeup will be used instead). where Gap is the gap in milli seconds between wakeup signal and wakeup event, or 0xff for special host sleep setting. Usage: # Use SDIO interface to wake up the host and set GAP to 0x80: echo 0xff80 > /debug/btmrvl/config/gpiogap echo 1 > /debug/btmrvl/config/hscfgcmd # Use GPIO pin #3 to wake up the host and set GAP to 0xff: echo 0x03ff > /debug/btmrvl/config/gpiogap echo 1 > /debug/btmrvl/config/hscfgcmd psmode=[n] pscmd These commands are used to enable/disable auto sleep mode where the option is: 1 -- Enable auto sleep mode 0 -- Disable auto sleep mode Usage: # Enable auto sleep mode echo 1 > /debug/btmrvl/config/psmode echo 1 > /debug/btmrvl/config/pscmd # Disable auto sleep mode echo 0 > /debug/btmrvl/config/psmode echo 1 > /debug/btmrvl/config/pscmd hsmode=[n] hscmd These commands are used to enable host sleep or wake up firmware where the option is: 1 -- Enable host sleep 0 -- Wake up firmware Usage: # Enable host sleep echo 1 > /debug/btmrvl/config/hsmode echo 1 > /debug/btmrvl/config/hscmd # Wake up firmware echo 0 > /debug/btmrvl/config/hsmode echo 1 > /debug/btmrvl/config/hscmd ====================== Get driver status: Path: /debug/btmrvl/status/ Usage: cat /debug/btmrvl/status/<args> where the args are: curpsmode This command displays current auto sleep status. psstate This command display the power save state. hsstate This command display the host sleep state. txdnldrdy This command displays the value of Tx download ready flag. ===================== Use hcitool to issue raw hci command, refer to hcitool manual Usage: Hcitool cmd <ogf> <ocf> [Parameters] Interface Control Command hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface ======================================================================= SD8688 firmware: /lib/firmware/sd8688_helper.bin /lib/firmware/sd8688.bin The images can be downloaded from: git.infradead.org/users/dwmw2/linux-firmware.git/libertas/ drivers/bluetooth/Kconfig +25 −0 Original line number Diff line number Diff line Loading @@ -170,5 +170,30 @@ config BT_HCIVHCI Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci). config BT_MRVL tristate "Marvell Bluetooth driver support" help The core driver to support Marvell Bluetooth devices. This driver is required if you want to support Marvell Bluetooth devices, such as 8688. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. config BT_MRVL_SDIO tristate "Marvell BT-over-SDIO driver" depends on BT_MRVL && MMC select FW_LOADER help The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth devices with SDIO interface. Currently only SD8688 chipset is supported. Say Y here to compile support for Marvell BT-over-SDIO driver into the kernel or say M to compile it as module. endmenu drivers/bluetooth/Makefile +6 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o Loading drivers/bluetooth/btmrvl_debugfs.c 0 → 100644 +432 −0 Original line number Diff line number Diff line /** * Marvell Bluetooth driver: debugfs related functions * * Copyright (C) 2009, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 * (the "License"). You may use, redistribute and/or modify this File in * accordance with the terms and conditions of the License, a copy of which * is available by writing to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. **/ #include <linux/debugfs.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "btmrvl_drv.h" struct btmrvl_debugfs_data { struct dentry *root_dir, *config_dir, *status_dir; /* config */ struct dentry *drvdbg; struct dentry *psmode; struct dentry *pscmd; struct dentry *hsmode; struct dentry *hscmd; struct dentry *gpiogap; struct dentry *hscfgcmd; /* status */ struct dentry *curpsmode; struct dentry *hsstate; struct dentry *psstate; struct dentry *txdnldready; }; static int btmrvl_open_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static ssize_t btmrvl_hscfgcmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hscfgcmd = result; if (priv->btmrvl_dev.hscfgcmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscfgcmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscfgcmd_fops = { .read = btmrvl_hscfgcmd_read, .write = btmrvl_hscfgcmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.psmode = result; return count; } static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psmode_fops = { .read = btmrvl_psmode_read, .write = btmrvl_psmode_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.pscmd = result; if (priv->btmrvl_dev.pscmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_pscmd_fops = { .read = btmrvl_pscmd_read, .write = btmrvl_pscmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 16, &result); priv->btmrvl_dev.gpio_gap = result; return count; } static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", priv->btmrvl_dev.gpio_gap); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_gpiogap_fops = { .read = btmrvl_gpiogap_read, .write = btmrvl_gpiogap_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hscmd = result; if (priv->btmrvl_dev.hscmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscmd_fops = { .read = btmrvl_hscmd_read, .write = btmrvl_hscmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hsmode = result; return count; } static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsmode_fops = { .read = btmrvl_hsmode_read, .write = btmrvl_hsmode_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_curpsmode_fops = { .read = btmrvl_curpsmode_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psstate_fops = { .read = btmrvl_psstate_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsstate_fops = { .read = btmrvl_hsstate_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.tx_dnld_rdy); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_txdnldready_fops = { .read = btmrvl_txdnldready_read, .open = btmrvl_open_generic, }; void btmrvl_debugfs_init(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg; dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); priv->debugfs_data = dbg; if (!dbg) { BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); return; } dbg->root_dir = debugfs_create_dir("btmrvl", NULL); dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg = priv->debugfs_data; if (!dbg) return; debugfs_remove(dbg->psmode); debugfs_remove(dbg->pscmd); debugfs_remove(dbg->gpiogap); debugfs_remove(dbg->hsmode); debugfs_remove(dbg->hscmd); debugfs_remove(dbg->hscfgcmd); debugfs_remove(dbg->config_dir); debugfs_remove(dbg->curpsmode); debugfs_remove(dbg->psstate); debugfs_remove(dbg->hsstate); debugfs_remove(dbg->txdnldready); debugfs_remove(dbg->status_dir); debugfs_remove(dbg->root_dir); kfree(dbg); } Loading
Documentation/00-INDEX +2 −0 Original line number Diff line number Diff line Loading @@ -82,6 +82,8 @@ block/ - info on the Block I/O (BIO) layer. blockdev/ - info on block devices & drivers btmrvl.txt - info on Marvell Bluetooth driver usage. cachetlb.txt - describes the cache/TLB flushing interfaces Linux uses. cdrom/ Loading
Documentation/btmrvl.txt 0 → 100644 +119 −0 Original line number Diff line number Diff line ======================================================================= README for btmrvl driver ======================================================================= All commands are used via debugfs interface. ===================== Set/get driver configurations: Path: /debug/btmrvl/config/ gpiogap=[n] hscfgcmd These commands are used to configure the host sleep parameters. bit 8:0 -- Gap bit 16:8 -- GPIO where GPIO is the pin number of GPIO used to wake up the host. It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface wakeup will be used instead). where Gap is the gap in milli seconds between wakeup signal and wakeup event, or 0xff for special host sleep setting. Usage: # Use SDIO interface to wake up the host and set GAP to 0x80: echo 0xff80 > /debug/btmrvl/config/gpiogap echo 1 > /debug/btmrvl/config/hscfgcmd # Use GPIO pin #3 to wake up the host and set GAP to 0xff: echo 0x03ff > /debug/btmrvl/config/gpiogap echo 1 > /debug/btmrvl/config/hscfgcmd psmode=[n] pscmd These commands are used to enable/disable auto sleep mode where the option is: 1 -- Enable auto sleep mode 0 -- Disable auto sleep mode Usage: # Enable auto sleep mode echo 1 > /debug/btmrvl/config/psmode echo 1 > /debug/btmrvl/config/pscmd # Disable auto sleep mode echo 0 > /debug/btmrvl/config/psmode echo 1 > /debug/btmrvl/config/pscmd hsmode=[n] hscmd These commands are used to enable host sleep or wake up firmware where the option is: 1 -- Enable host sleep 0 -- Wake up firmware Usage: # Enable host sleep echo 1 > /debug/btmrvl/config/hsmode echo 1 > /debug/btmrvl/config/hscmd # Wake up firmware echo 0 > /debug/btmrvl/config/hsmode echo 1 > /debug/btmrvl/config/hscmd ====================== Get driver status: Path: /debug/btmrvl/status/ Usage: cat /debug/btmrvl/status/<args> where the args are: curpsmode This command displays current auto sleep status. psstate This command display the power save state. hsstate This command display the host sleep state. txdnldrdy This command displays the value of Tx download ready flag. ===================== Use hcitool to issue raw hci command, refer to hcitool manual Usage: Hcitool cmd <ogf> <ocf> [Parameters] Interface Control Command hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface ======================================================================= SD8688 firmware: /lib/firmware/sd8688_helper.bin /lib/firmware/sd8688.bin The images can be downloaded from: git.infradead.org/users/dwmw2/linux-firmware.git/libertas/
drivers/bluetooth/Kconfig +25 −0 Original line number Diff line number Diff line Loading @@ -170,5 +170,30 @@ config BT_HCIVHCI Say Y here to compile support for virtual HCI devices into the kernel or say M to compile it as module (hci_vhci). config BT_MRVL tristate "Marvell Bluetooth driver support" help The core driver to support Marvell Bluetooth devices. This driver is required if you want to support Marvell Bluetooth devices, such as 8688. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. config BT_MRVL_SDIO tristate "Marvell BT-over-SDIO driver" depends on BT_MRVL && MMC select FW_LOADER help The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth devices with SDIO interface. Currently only SD8688 chipset is supported. Say Y here to compile support for Marvell BT-over-SDIO driver into the kernel or say M to compile it as module. endmenu
drivers/bluetooth/Makefile +6 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,12 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o obj-$(CONFIG_BT_MRVL) += btmrvl.o obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o hci_uart-y := hci_ldisc.o hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o Loading
drivers/bluetooth/btmrvl_debugfs.c 0 → 100644 +432 −0 Original line number Diff line number Diff line /** * Marvell Bluetooth driver: debugfs related functions * * Copyright (C) 2009, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 * (the "License"). You may use, redistribute and/or modify this File in * accordance with the terms and conditions of the License, a copy of which * is available by writing to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. **/ #include <linux/debugfs.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "btmrvl_drv.h" struct btmrvl_debugfs_data { struct dentry *root_dir, *config_dir, *status_dir; /* config */ struct dentry *drvdbg; struct dentry *psmode; struct dentry *pscmd; struct dentry *hsmode; struct dentry *hscmd; struct dentry *gpiogap; struct dentry *hscfgcmd; /* status */ struct dentry *curpsmode; struct dentry *hsstate; struct dentry *psstate; struct dentry *txdnldready; }; static int btmrvl_open_generic(struct inode *inode, struct file *file) { file->private_data = inode->i_private; return 0; } static ssize_t btmrvl_hscfgcmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hscfgcmd = result; if (priv->btmrvl_dev.hscfgcmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscfgcmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscfgcmd_fops = { .read = btmrvl_hscfgcmd_read, .write = btmrvl_hscfgcmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.psmode = result; return count; } static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psmode_fops = { .read = btmrvl_psmode_read, .write = btmrvl_psmode_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.pscmd = result; if (priv->btmrvl_dev.pscmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_pscmd_fops = { .read = btmrvl_pscmd_read, .write = btmrvl_pscmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 16, &result); priv->btmrvl_dev.gpio_gap = result; return count; } static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n", priv->btmrvl_dev.gpio_gap); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_gpiogap_fops = { .read = btmrvl_gpiogap_read, .write = btmrvl_gpiogap_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = (struct btmrvl_private *) file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hscmd = result; if (priv->btmrvl_dev.hscmd) { btmrvl_prepare_command(priv); wake_up_interruptible(&priv->main_thread.wait_q); } return count; } static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hscmd_fops = { .read = btmrvl_hscmd_read, .write = btmrvl_hscmd_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; long result, ret; memset(buf, 0, sizeof(buf)); if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; ret = strict_strtol(buf, 10, &result); priv->btmrvl_dev.hsmode = result; return count; } static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsmode_fops = { .read = btmrvl_hsmode_read, .write = btmrvl_hsmode_write, .open = btmrvl_open_generic, }; static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_curpsmode_fops = { .read = btmrvl_curpsmode_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_psstate_fops = { .read = btmrvl_psstate_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_hsstate_fops = { .read = btmrvl_hsstate_read, .open = btmrvl_open_generic, }; static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct btmrvl_private *priv = file->private_data; char buf[16]; int ret; ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.tx_dnld_rdy); return simple_read_from_buffer(userbuf, count, ppos, buf, ret); } static const struct file_operations btmrvl_txdnldready_fops = { .read = btmrvl_txdnldready_read, .open = btmrvl_open_generic, }; void btmrvl_debugfs_init(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg; dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); priv->debugfs_data = dbg; if (!dbg) { BT_ERR("Can not allocate memory for btmrvl_debugfs_data."); return; } dbg->root_dir = debugfs_create_dir("btmrvl", NULL); dbg->config_dir = debugfs_create_dir("config", dbg->root_dir); dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_psmode_fops); dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_pscmd_fops); dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_gpiogap_fops); dbg->hsmode = debugfs_create_file("hsmode", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hsmode_fops); dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscmd_fops); dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir, hdev->driver_data, &btmrvl_hscfgcmd_fops); dbg->status_dir = debugfs_create_dir("status", dbg->root_dir); dbg->curpsmode = debugfs_create_file("curpsmode", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_curpsmode_fops); dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_psstate_fops); dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_hsstate_fops); dbg->txdnldready = debugfs_create_file("txdnldready", 0444, dbg->status_dir, hdev->driver_data, &btmrvl_txdnldready_fops); } void btmrvl_debugfs_remove(struct hci_dev *hdev) { struct btmrvl_private *priv = hdev->driver_data; struct btmrvl_debugfs_data *dbg = priv->debugfs_data; if (!dbg) return; debugfs_remove(dbg->psmode); debugfs_remove(dbg->pscmd); debugfs_remove(dbg->gpiogap); debugfs_remove(dbg->hsmode); debugfs_remove(dbg->hscmd); debugfs_remove(dbg->hscfgcmd); debugfs_remove(dbg->config_dir); debugfs_remove(dbg->curpsmode); debugfs_remove(dbg->psstate); debugfs_remove(dbg->hsstate); debugfs_remove(dbg->txdnldready); debugfs_remove(dbg->status_dir); debugfs_remove(dbg->root_dir); kfree(dbg); }