blob: af31864c3a0f5f05d60dadb1bd489cd78df2e07e [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"
36#if defined(HIF_PCI)
37#include "if_pci.h"
38#elif defined(HIF_USB)
39#include "if_usb.h"
40#elif defined(HIF_SDIO)
41#include "if_ath_sdio.h"
42#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080043#include "hif_debug.h"
44
45#define PROCFS_NAME "athdiagpfs"
46#define PROCFS_DIR "cld"
47
48/**
49 * This structure hold information about the /proc file
50 *
51 */
52static struct proc_dir_entry *proc_file, *proc_dir;
53
54static void *get_hif_hdl_from_file(struct file *file)
55{
Komal Seelam5584a7c2016-02-24 19:22:48 +053056 struct hif_opaque_softc *scn;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080057
Komal Seelam5584a7c2016-02-24 19:22:48 +053058 scn = (struct hif_opaque_softc *)PDE_DATA(file_inode(file));
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080059 return (void *)scn;
60}
61
62static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
63 size_t count, loff_t *pos)
64{
65 hif_handle_t hif_hdl;
66 int rv;
67 uint8_t *read_buffer = NULL;
68
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053069 read_buffer = qdf_mem_malloc(count);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080070 if (NULL == read_buffer) {
71 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
72 return -ENOMEM;
73 }
74
75 hif_hdl = get_hif_hdl_from_file(file);
76 HIF_DBG("rd buff 0x%p cnt %zu offset 0x%x buf 0x%p",
77 read_buffer, count, (int)*pos, buf);
78
79 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
80 /* reading a word? */
81 rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
82 (uint32_t *)read_buffer);
83 } else {
84 rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
85 (uint8_t *)read_buffer, count);
86 }
87
88 if (copy_to_user(buf, read_buffer, count)) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053089 qdf_mem_free(read_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080090 HIF_ERROR("%s: copy_to_user error in /proc/%s",
91 __func__, PROCFS_NAME);
92 return -EFAULT;
93 } else
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053094 qdf_mem_free(read_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080095
96 if (rv == 0) {
97 return count;
98 } else {
99 return -EIO;
100 }
101}
102
103static ssize_t ath_procfs_diag_write(struct file *file,
104 const char __user *buf,
105 size_t count, loff_t *pos)
106{
107 hif_handle_t hif_hdl;
108 int rv;
109 uint8_t *write_buffer = NULL;
110
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530111 write_buffer = qdf_mem_malloc(count);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800112 if (NULL == write_buffer) {
113 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
114 return -ENOMEM;
115 }
116 if (copy_from_user(write_buffer, buf, count)) {
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530117 qdf_mem_free(write_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800118 HIF_ERROR("%s: copy_to_user error in /proc/%s",
119 __func__, PROCFS_NAME);
120 return -EFAULT;
121 }
122
123 hif_hdl = get_hif_hdl_from_file(file);
124 HIF_DBG("wr buff 0x%p buf 0x%p cnt %zu offset 0x%x value 0x%x",
125 write_buffer, buf, count,
126 (int)*pos, *((uint32_t *) write_buffer));
127
128 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
129 /* reading a word? */
130 uint32_t value = *((uint32_t *)write_buffer);
131 rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
132 } else {
133 rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
134 (uint8_t *)write_buffer, count);
135 }
136
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530137 qdf_mem_free(write_buffer);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800138 if (rv == 0) {
139 return count;
140 } else {
141 return -EIO;
142 }
143}
144
145static const struct file_operations athdiag_fops = {
146 .read = ath_procfs_diag_read,
147 .write = ath_procfs_diag_write,
148};
149
150/**
151 *This function is called when the module is loaded
152 *
153 */
154int athdiag_procfs_init(void *scn)
155{
156 proc_dir = proc_mkdir(PROCFS_DIR, NULL);
157 if (proc_dir == NULL) {
158 remove_proc_entry(PROCFS_DIR, NULL);
159 HIF_ERROR("%s: Error: Could not initialize /proc/%s",
160 __func__, PROCFS_DIR);
161 return -ENOMEM;
162 }
163
164 proc_file = proc_create_data(PROCFS_NAME,
165 S_IRUSR | S_IWUSR, proc_dir,
166 &athdiag_fops, (void *)scn);
167 if (proc_file == NULL) {
168 remove_proc_entry(PROCFS_NAME, proc_dir);
169 HIF_ERROR("%s: Could not initialize /proc/%s",
170 __func__, PROCFS_NAME);
171 return -ENOMEM;
172 }
173
174 HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
175 return 0; /* everything is ok */
176}
177
178/**
179 *This function is called when the module is unloaded
180 *
181 */
182void athdiag_procfs_remove(void)
183{
Karthick S6cd54a32015-10-14 18:39:56 +0530184 if (proc_dir != NULL) {
185 remove_proc_entry(PROCFS_NAME, proc_dir);
186 HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
187 remove_proc_entry(PROCFS_DIR, NULL);
188 HIF_DBG("/proc/%s removed", PROCFS_DIR);
189 proc_dir = NULL;
190 }
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800191}
192#else
193int athdiag_procfs_init(void *scn)
194{
195 return 0;
196}
197void athdiag_procfs_remove(void) {}
198#endif