194 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Marvell Bluetooth driver: debugfs related functions4 *5 * Copyright (C) 2009, Marvell International Ltd.6 **/7 8#include <linux/debugfs.h>9#include <linux/slab.h>10 11#include <net/bluetooth/bluetooth.h>12#include <net/bluetooth/hci_core.h>13 14#include "btmrvl_drv.h"15 16struct btmrvl_debugfs_data {17 struct dentry *config_dir;18 struct dentry *status_dir;19};20 21static ssize_t btmrvl_hscfgcmd_write(struct file *file,22 const char __user *ubuf, size_t count, loff_t *ppos)23{24 struct btmrvl_private *priv = file->private_data;25 long result, ret;26 27 ret = kstrtol_from_user(ubuf, count, 10, &result);28 if (ret)29 return ret;30 31 priv->btmrvl_dev.hscfgcmd = result;32 33 if (priv->btmrvl_dev.hscfgcmd) {34 btmrvl_prepare_command(priv);35 wake_up_interruptible(&priv->main_thread.wait_q);36 }37 38 return count;39}40 41static ssize_t btmrvl_hscfgcmd_read(struct file *file, char __user *userbuf,42 size_t count, loff_t *ppos)43{44 struct btmrvl_private *priv = file->private_data;45 char buf[16];46 int ret;47 48 ret = snprintf(buf, sizeof(buf) - 1, "%d\n",49 priv->btmrvl_dev.hscfgcmd);50 51 return simple_read_from_buffer(userbuf, count, ppos, buf, ret);52}53 54static const struct file_operations btmrvl_hscfgcmd_fops = {55 .read = btmrvl_hscfgcmd_read,56 .write = btmrvl_hscfgcmd_write,57 .open = simple_open,58 .llseek = default_llseek,59};60 61static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,62 size_t count, loff_t *ppos)63{64 struct btmrvl_private *priv = file->private_data;65 long result, ret;66 67 ret = kstrtol_from_user(ubuf, count, 10, &result);68 if (ret)69 return ret;70 71 priv->btmrvl_dev.pscmd = result;72 73 if (priv->btmrvl_dev.pscmd) {74 btmrvl_prepare_command(priv);75 wake_up_interruptible(&priv->main_thread.wait_q);76 }77 78 return count;79 80}81 82static ssize_t btmrvl_pscmd_read(struct file *file, char __user *userbuf,83 size_t count, loff_t *ppos)84{85 struct btmrvl_private *priv = file->private_data;86 char buf[16];87 int ret;88 89 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.pscmd);90 91 return simple_read_from_buffer(userbuf, count, ppos, buf, ret);92}93 94static const struct file_operations btmrvl_pscmd_fops = {95 .read = btmrvl_pscmd_read,96 .write = btmrvl_pscmd_write,97 .open = simple_open,98 .llseek = default_llseek,99};100 101static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,102 size_t count, loff_t *ppos)103{104 struct btmrvl_private *priv = file->private_data;105 long result, ret;106 107 ret = kstrtol_from_user(ubuf, count, 10, &result);108 if (ret)109 return ret;110 111 priv->btmrvl_dev.hscmd = result;112 if (priv->btmrvl_dev.hscmd) {113 btmrvl_prepare_command(priv);114 wake_up_interruptible(&priv->main_thread.wait_q);115 }116 117 return count;118}119 120static ssize_t btmrvl_hscmd_read(struct file *file, char __user *userbuf,121 size_t count, loff_t *ppos)122{123 struct btmrvl_private *priv = file->private_data;124 char buf[16];125 int ret;126 127 ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hscmd);128 129 return simple_read_from_buffer(userbuf, count, ppos, buf, ret);130}131 132static const struct file_operations btmrvl_hscmd_fops = {133 .read = btmrvl_hscmd_read,134 .write = btmrvl_hscmd_write,135 .open = simple_open,136 .llseek = default_llseek,137};138 139void btmrvl_debugfs_init(struct hci_dev *hdev)140{141 struct btmrvl_private *priv = hci_get_drvdata(hdev);142 struct btmrvl_debugfs_data *dbg;143 144 if (!hdev->debugfs)145 return;146 147 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);148 priv->debugfs_data = dbg;149 150 if (!dbg) {151 BT_ERR("Can not allocate memory for btmrvl_debugfs_data.");152 return;153 }154 155 dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);156 157 debugfs_create_u8("psmode", 0644, dbg->config_dir,158 &priv->btmrvl_dev.psmode);159 debugfs_create_file("pscmd", 0644, dbg->config_dir,160 priv, &btmrvl_pscmd_fops);161 debugfs_create_x16("gpiogap", 0644, dbg->config_dir,162 &priv->btmrvl_dev.gpio_gap);163 debugfs_create_u8("hsmode", 0644, dbg->config_dir,164 &priv->btmrvl_dev.hsmode);165 debugfs_create_file("hscmd", 0644, dbg->config_dir,166 priv, &btmrvl_hscmd_fops);167 debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,168 priv, &btmrvl_hscfgcmd_fops);169 170 dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);171 debugfs_create_u8("curpsmode", 0444, dbg->status_dir,172 &priv->adapter->psmode);173 debugfs_create_u8("psstate", 0444, dbg->status_dir,174 &priv->adapter->ps_state);175 debugfs_create_u8("hsstate", 0444, dbg->status_dir,176 &priv->adapter->hs_state);177 debugfs_create_u8("txdnldready", 0444, dbg->status_dir,178 &priv->btmrvl_dev.tx_dnld_rdy);179}180 181void btmrvl_debugfs_remove(struct hci_dev *hdev)182{183 struct btmrvl_private *priv = hci_get_drvdata(hdev);184 struct btmrvl_debugfs_data *dbg = priv->debugfs_data;185 186 if (!dbg)187 return;188 189 debugfs_remove_recursive(dbg->config_dir);190 debugfs_remove_recursive(dbg->status_dir);191 192 kfree(dbg);193}194