blob: a20f88648ef82da5ba4b5a0bd97cb8928af6e93c [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Komal Seelambd7c51d2016-02-24 10:27:30 +05302 * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28#if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT)
29#include <linux/module.h> /* Specifically, a module */
30#include <linux/kernel.h> /* We're doing kernel work */
31#include <linux/version.h> /* We're doing kernel work */
32#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
33#include <asm/uaccess.h> /* for copy_from_user */
34#include "ol_if_athvar.h"
35#include "hif.h"
Houston Hoffmanbc693492016-03-14 21:11:41 -070036#if defined(HIF_USB)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080037#include "if_usb.h"
Houston Hoffmanbc693492016-03-14 21:11:41 -070038#endif
39#if defined(HIF_SDIO)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080040#include "if_ath_sdio.h"
41#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080042#include "hif_debug.h"
43
44#define PROCFS_NAME "athdiagpfs"
45#define PROCFS_DIR "cld"
46
47/**
48 * This structure hold information about the /proc file
49 *
50 */
51static struct proc_dir_entry *proc_file, *proc_dir;
52
53static void *get_hif_hdl_from_file(struct file *file)
54{
Komal Seelam5584a7c2016-02-24 19:22:48 +053055 struct hif_opaque_softc *scn;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080056
Komal Seelam5584a7c2016-02-24 19:22:48 +053057 scn = (struct hif_opaque_softc *)PDE_DATA(file_inode(file));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080058 return (void *)scn;
59}
60
61static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
62 size_t count, loff_t *pos)
63{
64 hif_handle_t hif_hdl;
65 int rv;
66 uint8_t *read_buffer = NULL;
67
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053068 read_buffer = qdf_mem_malloc(count);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080069 if (NULL == read_buffer) {
70 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
71 return -ENOMEM;
72 }
73
74 hif_hdl = get_hif_hdl_from_file(file);
75 HIF_DBG("rd buff 0x%p cnt %zu offset 0x%x buf 0x%p",
76 read_buffer, count, (int)*pos, buf);
77
78 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
79 /* reading a word? */
80 rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
81 (uint32_t *)read_buffer);
82 } else {
83 rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
84 (uint8_t *)read_buffer, count);
85 }
86
87 if (copy_to_user(buf, read_buffer, count)) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053088 qdf_mem_free(read_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080089 HIF_ERROR("%s: copy_to_user error in /proc/%s",
90 __func__, PROCFS_NAME);
91 return -EFAULT;
92 } else
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053093 qdf_mem_free(read_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080094
95 if (rv == 0) {
96 return count;
97 } else {
98 return -EIO;
99 }
100}
101
102static ssize_t ath_procfs_diag_write(struct file *file,
103 const char __user *buf,
104 size_t count, loff_t *pos)
105{
106 hif_handle_t hif_hdl;
107 int rv;
108 uint8_t *write_buffer = NULL;
109
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530110 write_buffer = qdf_mem_malloc(count);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800111 if (NULL == write_buffer) {
112 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
113 return -ENOMEM;
114 }
115 if (copy_from_user(write_buffer, buf, count)) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530116 qdf_mem_free(write_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800117 HIF_ERROR("%s: copy_to_user error in /proc/%s",
118 __func__, PROCFS_NAME);
119 return -EFAULT;
120 }
121
122 hif_hdl = get_hif_hdl_from_file(file);
123 HIF_DBG("wr buff 0x%p buf 0x%p cnt %zu offset 0x%x value 0x%x",
124 write_buffer, buf, count,
125 (int)*pos, *((uint32_t *) write_buffer));
126
127 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
128 /* reading a word? */
129 uint32_t value = *((uint32_t *)write_buffer);
130 rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
131 } else {
132 rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
133 (uint8_t *)write_buffer, count);
134 }
135
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530136 qdf_mem_free(write_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800137 if (rv == 0) {
138 return count;
139 } else {
140 return -EIO;
141 }
142}
143
144static const struct file_operations athdiag_fops = {
145 .read = ath_procfs_diag_read,
146 .write = ath_procfs_diag_write,
147};
148
149/**
150 *This function is called when the module is loaded
151 *
152 */
153int athdiag_procfs_init(void *scn)
154{
155 proc_dir = proc_mkdir(PROCFS_DIR, NULL);
156 if (proc_dir == NULL) {
157 remove_proc_entry(PROCFS_DIR, NULL);
158 HIF_ERROR("%s: Error: Could not initialize /proc/%s",
159 __func__, PROCFS_DIR);
160 return -ENOMEM;
161 }
162
163 proc_file = proc_create_data(PROCFS_NAME,
164 S_IRUSR | S_IWUSR, proc_dir,
165 &athdiag_fops, (void *)scn);
166 if (proc_file == NULL) {
167 remove_proc_entry(PROCFS_NAME, proc_dir);
168 HIF_ERROR("%s: Could not initialize /proc/%s",
169 __func__, PROCFS_NAME);
170 return -ENOMEM;
171 }
172
173 HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
174 return 0; /* everything is ok */
175}
176
177/**
178 *This function is called when the module is unloaded
179 *
180 */
181void athdiag_procfs_remove(void)
182{
Karthick S6cd54a32015-10-14 18:39:56 +0530183 if (proc_dir != NULL) {
184 remove_proc_entry(PROCFS_NAME, proc_dir);
185 HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
186 remove_proc_entry(PROCFS_DIR, NULL);
187 HIF_DBG("/proc/%s removed", PROCFS_DIR);
188 proc_dir = NULL;
189 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800190}
191#else
192int athdiag_procfs_init(void *scn)
193{
194 return 0;
195}
196void athdiag_procfs_remove(void) {}
197#endif