blob: 48b3021e146bdafc571c8563e5d7249ae55d45ae [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
2 * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved.
3 *
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
43#include "cds_api.h"
44#include "hif_debug.h"
45
46#define PROCFS_NAME "athdiagpfs"
47#define PROCFS_DIR "cld"
48
49/**
50 * This structure hold information about the /proc file
51 *
52 */
53static struct proc_dir_entry *proc_file, *proc_dir;
54
55static void *get_hif_hdl_from_file(struct file *file)
56{
57 struct ol_softc *scn;
58
59#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0))
60 scn = (struct ol_softc *)PDE_DATA(file_inode(file));
61#else
62 scn = (struct ol_softc *)(
63 PDE(file->f_path.dentry->d_inode)->data);
64#endif
65 return (void *)scn;
66}
67
68static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf,
69 size_t count, loff_t *pos)
70{
71 hif_handle_t hif_hdl;
72 int rv;
73 uint8_t *read_buffer = NULL;
74
75 read_buffer = cdf_mem_malloc(count);
76 if (NULL == read_buffer) {
77 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
78 return -ENOMEM;
79 }
80
81 hif_hdl = get_hif_hdl_from_file(file);
82 HIF_DBG("rd buff 0x%p cnt %zu offset 0x%x buf 0x%p",
83 read_buffer, count, (int)*pos, buf);
84
85 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
86 /* reading a word? */
87 rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos),
88 (uint32_t *)read_buffer);
89 } else {
90 rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos),
91 (uint8_t *)read_buffer, count);
92 }
93
94 if (copy_to_user(buf, read_buffer, count)) {
95 cdf_mem_free(read_buffer);
96 HIF_ERROR("%s: copy_to_user error in /proc/%s",
97 __func__, PROCFS_NAME);
98 return -EFAULT;
99 } else
100 cdf_mem_free(read_buffer);
101
102 if (rv == 0) {
103 return count;
104 } else {
105 return -EIO;
106 }
107}
108
109static ssize_t ath_procfs_diag_write(struct file *file,
110 const char __user *buf,
111 size_t count, loff_t *pos)
112{
113 hif_handle_t hif_hdl;
114 int rv;
115 uint8_t *write_buffer = NULL;
116
117 write_buffer = cdf_mem_malloc(count);
118 if (NULL == write_buffer) {
119 HIF_ERROR("%s: cdf_mem_alloc failed", __func__);
120 return -ENOMEM;
121 }
122 if (copy_from_user(write_buffer, buf, count)) {
123 cdf_mem_free(write_buffer);
124 HIF_ERROR("%s: copy_to_user error in /proc/%s",
125 __func__, PROCFS_NAME);
126 return -EFAULT;
127 }
128
129 hif_hdl = get_hif_hdl_from_file(file);
130 HIF_DBG("wr buff 0x%p buf 0x%p cnt %zu offset 0x%x value 0x%x",
131 write_buffer, buf, count,
132 (int)*pos, *((uint32_t *) write_buffer));
133
134 if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) {
135 /* reading a word? */
136 uint32_t value = *((uint32_t *)write_buffer);
137 rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value);
138 } else {
139 rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos),
140 (uint8_t *)write_buffer, count);
141 }
142
143 cdf_mem_free(write_buffer);
144 if (rv == 0) {
145 return count;
146 } else {
147 return -EIO;
148 }
149}
150
151static const struct file_operations athdiag_fops = {
152 .read = ath_procfs_diag_read,
153 .write = ath_procfs_diag_write,
154};
155
156/**
157 *This function is called when the module is loaded
158 *
159 */
160int athdiag_procfs_init(void *scn)
161{
162 proc_dir = proc_mkdir(PROCFS_DIR, NULL);
163 if (proc_dir == NULL) {
164 remove_proc_entry(PROCFS_DIR, NULL);
165 HIF_ERROR("%s: Error: Could not initialize /proc/%s",
166 __func__, PROCFS_DIR);
167 return -ENOMEM;
168 }
169
170 proc_file = proc_create_data(PROCFS_NAME,
171 S_IRUSR | S_IWUSR, proc_dir,
172 &athdiag_fops, (void *)scn);
173 if (proc_file == NULL) {
174 remove_proc_entry(PROCFS_NAME, proc_dir);
175 HIF_ERROR("%s: Could not initialize /proc/%s",
176 __func__, PROCFS_NAME);
177 return -ENOMEM;
178 }
179
180 HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME);
181 return 0; /* everything is ok */
182}
183
184/**
185 *This function is called when the module is unloaded
186 *
187 */
188void athdiag_procfs_remove(void)
189{
190 remove_proc_entry(PROCFS_NAME, proc_dir);
191 HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME);
192 remove_proc_entry(PROCFS_DIR, NULL);
193 HIF_DBG("/proc/%s removed", PROCFS_DIR);
194}
195#else
196int athdiag_procfs_init(void *scn)
197{
198 return 0;
199}
200void athdiag_procfs_remove(void) {}
201#endif