Commit | Line | Data |
---|---|---|
876c9d3a MT |
1 | #include <linux/module.h> |
2 | #include <linux/dcache.h> | |
3 | #include <linux/debugfs.h> | |
4 | #include <linux/delay.h> | |
5 | #include <linux/mm.h> | |
d8b0fb51 | 6 | #include <linux/string.h> |
5a0e3ad6 | 7 | #include <linux/slab.h> |
876c9d3a | 8 | #include <net/iw_handler.h> |
7e272fcf | 9 | #include <net/lib80211.h> |
46868202 | 10 | |
876c9d3a MT |
11 | #include "dev.h" |
12 | #include "decl.h" | |
13 | #include "host.h" | |
5bdb3efe | 14 | #include "debugfs.h" |
3fbe104c | 15 | #include "cmd.h" |
876c9d3a | 16 | |
10078321 | 17 | static struct dentry *lbs_dir; |
876c9d3a MT |
18 | static char *szStates[] = { |
19 | "Connected", | |
20 | "Disconnected" | |
21 | }; | |
22 | ||
46868202 | 23 | #ifdef PROC_DEBUG |
e98a88dd | 24 | static void lbs_debug_init(struct lbs_private *priv); |
46868202 | 25 | #endif |
876c9d3a MT |
26 | |
27 | static int open_file_generic(struct inode *inode, struct file *file) | |
28 | { | |
29 | file->private_data = inode->i_private; | |
30 | return 0; | |
31 | } | |
32 | ||
33 | static ssize_t write_file_dummy(struct file *file, const char __user *buf, | |
34 | size_t count, loff_t *ppos) | |
35 | { | |
36 | return -EINVAL; | |
37 | } | |
38 | ||
39 | static const size_t len = PAGE_SIZE; | |
40 | ||
10078321 | 41 | static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, |
876c9d3a MT |
42 | size_t count, loff_t *ppos) |
43 | { | |
69f9032d | 44 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
45 | size_t pos = 0; |
46 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
47 | char *buf = (char *)addr; | |
48 | ssize_t res; | |
ad43f8bf KD |
49 | if (!buf) |
50 | return -ENOMEM; | |
876c9d3a MT |
51 | |
52 | pos += snprintf(buf+pos, len-pos, "state = %s\n", | |
aa21c004 | 53 | szStates[priv->connect_status]); |
876c9d3a | 54 | pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", |
aa21c004 | 55 | (u32) priv->regioncode); |
876c9d3a MT |
56 | |
57 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | |
58 | ||
59 | free_page(addr); | |
60 | return res; | |
61 | } | |
62 | ||
63 | ||
10078321 | 64 | static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, |
876c9d3a MT |
65 | size_t count, loff_t *ppos) |
66 | { | |
69f9032d | 67 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
68 | size_t pos = 0; |
69 | int numscansdone = 0, res; | |
70 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
71 | char *buf = (char *)addr; | |
9387b7ca | 72 | DECLARE_SSID_BUF(ssid); |
fcdb53db | 73 | struct bss_descriptor * iter_bss; |
ad43f8bf KD |
74 | if (!buf) |
75 | return -ENOMEM; | |
876c9d3a | 76 | |
876c9d3a | 77 | pos += snprintf(buf+pos, len-pos, |
a2235ed4 | 78 | "# | ch | rssi | bssid | cap | Qual | SSID \n"); |
876c9d3a | 79 | |
aa21c004 DW |
80 | mutex_lock(&priv->lock); |
81 | list_for_each_entry (iter_bss, &priv->network_list, list) { | |
0c9ca690 DW |
82 | u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); |
83 | u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); | |
84 | u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); | |
876c9d3a | 85 | |
e174961c | 86 | pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", |
fcdb53db | 87 | numscansdone, iter_bss->channel, iter_bss->rssi, |
e174961c | 88 | iter_bss->bssid); |
0c9ca690 | 89 | pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); |
876c9d3a | 90 | pos += snprintf(buf+pos, len-pos, "%c%c%c |", |
0c9ca690 DW |
91 | ibss ? 'A' : 'I', privacy ? 'P' : ' ', |
92 | spectrum_mgmt ? 'S' : ' '); | |
a2235ed4 | 93 | pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); |
d8efea25 | 94 | pos += snprintf(buf+pos, len-pos, " %s\n", |
9387b7ca JL |
95 | print_ssid(ssid, iter_bss->ssid, |
96 | iter_bss->ssid_len)); | |
876c9d3a MT |
97 | |
98 | numscansdone++; | |
99 | } | |
aa21c004 | 100 | mutex_unlock(&priv->lock); |
876c9d3a MT |
101 | |
102 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | |
103 | ||
104 | free_page(addr); | |
105 | return res; | |
106 | } | |
107 | ||
10078321 | 108 | static ssize_t lbs_sleepparams_write(struct file *file, |
876c9d3a MT |
109 | const char __user *user_buf, size_t count, |
110 | loff_t *ppos) | |
111 | { | |
69f9032d | 112 | struct lbs_private *priv = file->private_data; |
3fbe104c DW |
113 | ssize_t buf_size, ret; |
114 | struct sleep_params sp; | |
876c9d3a | 115 | int p1, p2, p3, p4, p5, p6; |
876c9d3a MT |
116 | unsigned long addr = get_zeroed_page(GFP_KERNEL); |
117 | char *buf = (char *)addr; | |
ad43f8bf KD |
118 | if (!buf) |
119 | return -ENOMEM; | |
876c9d3a MT |
120 | |
121 | buf_size = min(count, len - 1); | |
122 | if (copy_from_user(buf, user_buf, buf_size)) { | |
3fbe104c | 123 | ret = -EFAULT; |
876c9d3a MT |
124 | goto out_unlock; |
125 | } | |
3fbe104c DW |
126 | ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); |
127 | if (ret != 6) { | |
128 | ret = -EINVAL; | |
876c9d3a MT |
129 | goto out_unlock; |
130 | } | |
3fbe104c DW |
131 | sp.sp_error = p1; |
132 | sp.sp_offset = p2; | |
133 | sp.sp_stabletime = p3; | |
134 | sp.sp_calcontrol = p4; | |
135 | sp.sp_extsleepclk = p5; | |
136 | sp.sp_reserved = p6; | |
137 | ||
138 | ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp); | |
139 | if (!ret) | |
140 | ret = count; | |
141 | else if (ret > 0) | |
142 | ret = -EINVAL; | |
876c9d3a MT |
143 | |
144 | out_unlock: | |
145 | free_page(addr); | |
3fbe104c | 146 | return ret; |
876c9d3a MT |
147 | } |
148 | ||
10078321 | 149 | static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, |
876c9d3a MT |
150 | size_t count, loff_t *ppos) |
151 | { | |
69f9032d | 152 | struct lbs_private *priv = file->private_data; |
3fbe104c | 153 | ssize_t ret; |
876c9d3a | 154 | size_t pos = 0; |
3fbe104c | 155 | struct sleep_params sp; |
876c9d3a MT |
156 | unsigned long addr = get_zeroed_page(GFP_KERNEL); |
157 | char *buf = (char *)addr; | |
ad43f8bf KD |
158 | if (!buf) |
159 | return -ENOMEM; | |
876c9d3a | 160 | |
3fbe104c DW |
161 | ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); |
162 | if (ret) | |
876c9d3a | 163 | goto out_unlock; |
876c9d3a | 164 | |
3fbe104c DW |
165 | pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error, |
166 | sp.sp_offset, sp.sp_stabletime, | |
167 | sp.sp_calcontrol, sp.sp_extsleepclk, | |
168 | sp.sp_reserved); | |
876c9d3a | 169 | |
3fbe104c | 170 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
876c9d3a MT |
171 | |
172 | out_unlock: | |
173 | free_page(addr); | |
3fbe104c | 174 | return ret; |
876c9d3a MT |
175 | } |
176 | ||
3a188649 HS |
177 | /* |
178 | * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might | |
179 | * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the | |
180 | * firmware. Here's an example: | |
181 | * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00 | |
182 | * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03 | |
183 | * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | |
184 | * | |
185 | * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length, | |
186 | * 00 00 are the data bytes of this TLV. For this TLV, their meaning is | |
187 | * defined in mrvlietypes_thresholds | |
188 | * | |
189 | * This function searches in this TLV data chunk for a given TLV type | |
190 | * and returns a pointer to the first data byte of the TLV, or to NULL | |
191 | * if the TLV hasn't been found. | |
192 | */ | |
5844d12e | 193 | static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) |
876c9d3a | 194 | { |
75b6a61a | 195 | struct mrvl_ie_header *tlv_h; |
5844d12e DW |
196 | uint16_t length; |
197 | ssize_t pos = 0; | |
198 | ||
3a188649 | 199 | while (pos < size) { |
75b6a61a | 200 | tlv_h = (struct mrvl_ie_header *) tlv; |
5844d12e | 201 | if (!tlv_h->len) |
3a188649 | 202 | return NULL; |
5844d12e DW |
203 | if (tlv_h->type == cpu_to_le16(tlv_type)) |
204 | return tlv_h; | |
205 | length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h); | |
3a188649 HS |
206 | pos += length; |
207 | tlv += length; | |
208 | } | |
209 | return NULL; | |
876c9d3a MT |
210 | } |
211 | ||
3a188649 | 212 | |
5844d12e DW |
213 | static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, |
214 | struct file *file, char __user *userbuf, | |
215 | size_t count, loff_t *ppos) | |
876c9d3a | 216 | { |
5844d12e | 217 | struct cmd_ds_802_11_subscribe_event *subscribed; |
75b6a61a | 218 | struct mrvl_ie_thresholds *got; |
69f9032d | 219 | struct lbs_private *priv = file->private_data; |
5844d12e | 220 | ssize_t ret = 0; |
3a188649 | 221 | size_t pos = 0; |
5844d12e | 222 | char *buf; |
3a188649 HS |
223 | u8 value; |
224 | u8 freq; | |
b6b8abe4 | 225 | int events = 0; |
876c9d3a | 226 | |
5844d12e DW |
227 | buf = (char *)get_zeroed_page(GFP_KERNEL); |
228 | if (!buf) | |
229 | return -ENOMEM; | |
876c9d3a | 230 | |
5844d12e DW |
231 | subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL); |
232 | if (!subscribed) { | |
233 | ret = -ENOMEM; | |
234 | goto out_page; | |
876c9d3a MT |
235 | } |
236 | ||
5844d12e DW |
237 | subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed)); |
238 | subscribed->action = cpu_to_le16(CMD_ACT_GET); | |
239 | ||
240 | ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed); | |
241 | if (ret) | |
242 | goto out_cmd; | |
243 | ||
b6b8abe4 | 244 | got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); |
3a188649 HS |
245 | if (got) { |
246 | value = got->value; | |
247 | freq = got->freq; | |
b6b8abe4 | 248 | events = le16_to_cpu(subscribed->events); |
876c9d3a | 249 | |
3a188649 | 250 | pos += snprintf(buf, len, "%d %d %d\n", value, freq, |
5844d12e DW |
251 | !!(events & event_mask)); |
252 | } | |
876c9d3a | 253 | |
5844d12e | 254 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
876c9d3a | 255 | |
5844d12e DW |
256 | out_cmd: |
257 | kfree(subscribed); | |
258 | ||
259 | out_page: | |
260 | free_page((unsigned long)buf); | |
261 | return ret; | |
876c9d3a MT |
262 | } |
263 | ||
876c9d3a | 264 | |
5844d12e DW |
265 | static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, |
266 | struct file *file, | |
267 | const char __user *userbuf, size_t count, | |
268 | loff_t *ppos) | |
876c9d3a | 269 | { |
3a188649 | 270 | struct cmd_ds_802_11_subscribe_event *events; |
75b6a61a | 271 | struct mrvl_ie_thresholds *tlv; |
5844d12e DW |
272 | struct lbs_private *priv = file->private_data; |
273 | ssize_t buf_size; | |
274 | int value, freq, new_mask; | |
275 | uint16_t curr_mask; | |
276 | char *buf; | |
277 | int ret; | |
278 | ||
279 | buf = (char *)get_zeroed_page(GFP_KERNEL); | |
280 | if (!buf) | |
281 | return -ENOMEM; | |
876c9d3a MT |
282 | |
283 | buf_size = min(count, len - 1); | |
284 | if (copy_from_user(buf, userbuf, buf_size)) { | |
5844d12e DW |
285 | ret = -EFAULT; |
286 | goto out_page; | |
876c9d3a | 287 | } |
5844d12e DW |
288 | ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); |
289 | if (ret != 3) { | |
290 | ret = -EINVAL; | |
291 | goto out_page; | |
292 | } | |
293 | events = kzalloc(sizeof(*events), GFP_KERNEL); | |
294 | if (!events) { | |
295 | ret = -ENOMEM; | |
296 | goto out_page; | |
876c9d3a | 297 | } |
5844d12e DW |
298 | |
299 | events->hdr.size = cpu_to_le16(sizeof(*events)); | |
300 | events->action = cpu_to_le16(CMD_ACT_GET); | |
301 | ||
302 | ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); | |
303 | if (ret) | |
304 | goto out_events; | |
305 | ||
306 | curr_mask = le16_to_cpu(events->events); | |
876c9d3a | 307 | |
3a188649 HS |
308 | if (new_mask) |
309 | new_mask = curr_mask | event_mask; | |
310 | else | |
311 | new_mask = curr_mask & ~event_mask; | |
312 | ||
313 | /* Now everything is set and we can send stuff down to the firmware */ | |
876c9d3a | 314 | |
5844d12e DW |
315 | tlv = (void *)events->tlv; |
316 | ||
317 | events->action = cpu_to_le16(CMD_ACT_SET); | |
318 | events->events = cpu_to_le16(new_mask); | |
319 | tlv->header.type = cpu_to_le16(tlv_type); | |
320 | tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header)); | |
321 | tlv->value = value; | |
322 | if (tlv_type != TLV_TYPE_BCNMISS) | |
323 | tlv->freq = freq; | |
324 | ||
a75eda43 HS |
325 | /* The command header, the action, the event mask, and one TLV */ |
326 | events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv)); | |
5844d12e DW |
327 | |
328 | ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); | |
329 | ||
330 | if (!ret) | |
331 | ret = count; | |
332 | out_events: | |
333 | kfree(events); | |
334 | out_page: | |
335 | free_page((unsigned long)buf); | |
336 | return ret; | |
876c9d3a MT |
337 | } |
338 | ||
876c9d3a | 339 | |
5844d12e DW |
340 | static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf, |
341 | size_t count, loff_t *ppos) | |
876c9d3a | 342 | { |
3a188649 | 343 | return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, |
5844d12e | 344 | file, userbuf, count, ppos); |
876c9d3a MT |
345 | } |
346 | ||
876c9d3a | 347 | |
5844d12e DW |
348 | static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf, |
349 | size_t count, loff_t *ppos) | |
3a188649 HS |
350 | { |
351 | return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, | |
5844d12e | 352 | file, userbuf, count, ppos); |
3a188649 | 353 | } |
876c9d3a | 354 | |
876c9d3a | 355 | |
5844d12e DW |
356 | static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf, |
357 | size_t count, loff_t *ppos) | |
3a188649 HS |
358 | { |
359 | return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, | |
5844d12e | 360 | file, userbuf, count, ppos); |
3a188649 | 361 | } |
876c9d3a | 362 | |
876c9d3a | 363 | |
5844d12e DW |
364 | static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf, |
365 | size_t count, loff_t *ppos) | |
3a188649 HS |
366 | { |
367 | return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, | |
5844d12e | 368 | file, userbuf, count, ppos); |
3a188649 | 369 | } |
876c9d3a | 370 | |
876c9d3a | 371 | |
5844d12e DW |
372 | static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf, |
373 | size_t count, loff_t *ppos) | |
3a188649 HS |
374 | { |
375 | return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, | |
5844d12e | 376 | file, userbuf, count, ppos); |
3a188649 | 377 | } |
876c9d3a | 378 | |
876c9d3a | 379 | |
5844d12e DW |
380 | static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf, |
381 | size_t count, loff_t *ppos) | |
3a188649 HS |
382 | { |
383 | return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, | |
5844d12e | 384 | file, userbuf, count, ppos); |
876c9d3a MT |
385 | } |
386 | ||
3a188649 | 387 | |
5844d12e DW |
388 | static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf, |
389 | size_t count, loff_t *ppos) | |
876c9d3a | 390 | { |
3a188649 | 391 | return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, |
5844d12e | 392 | file, userbuf, count, ppos); |
3a188649 | 393 | } |
876c9d3a | 394 | |
876c9d3a | 395 | |
5844d12e DW |
396 | static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf, |
397 | size_t count, loff_t *ppos) | |
3a188649 HS |
398 | { |
399 | return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, | |
5844d12e | 400 | file, userbuf, count, ppos); |
3a188649 | 401 | } |
876c9d3a | 402 | |
876c9d3a | 403 | |
5844d12e DW |
404 | static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, |
405 | size_t count, loff_t *ppos) | |
3a188649 HS |
406 | { |
407 | return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, | |
5844d12e | 408 | file, userbuf, count, ppos); |
3a188649 | 409 | } |
876c9d3a | 410 | |
876c9d3a | 411 | |
5844d12e DW |
412 | static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf, |
413 | size_t count, loff_t *ppos) | |
3a188649 HS |
414 | { |
415 | return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, | |
5844d12e | 416 | file, userbuf, count, ppos); |
876c9d3a MT |
417 | } |
418 | ||
5844d12e DW |
419 | static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf, |
420 | size_t count, loff_t *ppos) | |
876c9d3a | 421 | { |
3a188649 | 422 | return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, |
5844d12e | 423 | file, userbuf, count, ppos); |
3a188649 | 424 | } |
876c9d3a | 425 | |
876c9d3a | 426 | |
5844d12e DW |
427 | static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf, |
428 | size_t count, loff_t *ppos) | |
3a188649 HS |
429 | { |
430 | return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, | |
5844d12e | 431 | file, userbuf, count, ppos); |
876c9d3a MT |
432 | } |
433 | ||
876c9d3a | 434 | |
876c9d3a | 435 | |
10078321 | 436 | static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, |
876c9d3a MT |
437 | size_t count, loff_t *ppos) |
438 | { | |
69f9032d | 439 | struct lbs_private *priv = file->private_data; |
10078321 | 440 | struct lbs_offset_value offval; |
876c9d3a MT |
441 | ssize_t pos = 0; |
442 | int ret; | |
443 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
444 | char *buf = (char *)addr; | |
ad43f8bf KD |
445 | if (!buf) |
446 | return -ENOMEM; | |
876c9d3a MT |
447 | |
448 | offval.offset = priv->mac_offset; | |
449 | offval.value = 0; | |
450 | ||
10078321 | 451 | ret = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
452 | CMD_MAC_REG_ACCESS, 0, |
453 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a | 454 | mdelay(10); |
c0bbd576 AK |
455 | if (!ret) { |
456 | pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", | |
aa21c004 | 457 | priv->mac_offset, priv->offsetvalue.value); |
876c9d3a | 458 | |
c0bbd576 AK |
459 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
460 | } | |
876c9d3a MT |
461 | free_page(addr); |
462 | return ret; | |
463 | } | |
464 | ||
10078321 | 465 | static ssize_t lbs_rdmac_write(struct file *file, |
876c9d3a MT |
466 | const char __user *userbuf, |
467 | size_t count, loff_t *ppos) | |
468 | { | |
69f9032d | 469 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
470 | ssize_t res, buf_size; |
471 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
472 | char *buf = (char *)addr; | |
ad43f8bf KD |
473 | if (!buf) |
474 | return -ENOMEM; | |
876c9d3a MT |
475 | |
476 | buf_size = min(count, len - 1); | |
477 | if (copy_from_user(buf, userbuf, buf_size)) { | |
478 | res = -EFAULT; | |
479 | goto out_unlock; | |
480 | } | |
481 | priv->mac_offset = simple_strtoul((char *)buf, NULL, 16); | |
482 | res = count; | |
483 | out_unlock: | |
484 | free_page(addr); | |
485 | return res; | |
486 | } | |
487 | ||
10078321 | 488 | static ssize_t lbs_wrmac_write(struct file *file, |
876c9d3a MT |
489 | const char __user *userbuf, |
490 | size_t count, loff_t *ppos) | |
491 | { | |
492 | ||
69f9032d | 493 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
494 | ssize_t res, buf_size; |
495 | u32 offset, value; | |
10078321 | 496 | struct lbs_offset_value offval; |
876c9d3a MT |
497 | unsigned long addr = get_zeroed_page(GFP_KERNEL); |
498 | char *buf = (char *)addr; | |
ad43f8bf KD |
499 | if (!buf) |
500 | return -ENOMEM; | |
876c9d3a MT |
501 | |
502 | buf_size = min(count, len - 1); | |
503 | if (copy_from_user(buf, userbuf, buf_size)) { | |
504 | res = -EFAULT; | |
505 | goto out_unlock; | |
506 | } | |
507 | res = sscanf(buf, "%x %x", &offset, &value); | |
508 | if (res != 2) { | |
509 | res = -EFAULT; | |
510 | goto out_unlock; | |
511 | } | |
512 | ||
513 | offval.offset = offset; | |
514 | offval.value = value; | |
10078321 | 515 | res = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
516 | CMD_MAC_REG_ACCESS, 1, |
517 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a MT |
518 | mdelay(10); |
519 | ||
c0bbd576 AK |
520 | if (!res) |
521 | res = count; | |
876c9d3a MT |
522 | out_unlock: |
523 | free_page(addr); | |
524 | return res; | |
525 | } | |
526 | ||
10078321 | 527 | static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, |
876c9d3a MT |
528 | size_t count, loff_t *ppos) |
529 | { | |
69f9032d | 530 | struct lbs_private *priv = file->private_data; |
10078321 | 531 | struct lbs_offset_value offval; |
876c9d3a MT |
532 | ssize_t pos = 0; |
533 | int ret; | |
534 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
535 | char *buf = (char *)addr; | |
ad43f8bf KD |
536 | if (!buf) |
537 | return -ENOMEM; | |
876c9d3a MT |
538 | |
539 | offval.offset = priv->bbp_offset; | |
540 | offval.value = 0; | |
541 | ||
10078321 | 542 | ret = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
543 | CMD_BBP_REG_ACCESS, 0, |
544 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a | 545 | mdelay(10); |
c0bbd576 AK |
546 | if (!ret) { |
547 | pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", | |
aa21c004 | 548 | priv->bbp_offset, priv->offsetvalue.value); |
876c9d3a | 549 | |
c0bbd576 AK |
550 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
551 | } | |
876c9d3a MT |
552 | free_page(addr); |
553 | ||
554 | return ret; | |
555 | } | |
556 | ||
10078321 | 557 | static ssize_t lbs_rdbbp_write(struct file *file, |
876c9d3a MT |
558 | const char __user *userbuf, |
559 | size_t count, loff_t *ppos) | |
560 | { | |
69f9032d | 561 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
562 | ssize_t res, buf_size; |
563 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
564 | char *buf = (char *)addr; | |
ad43f8bf KD |
565 | if (!buf) |
566 | return -ENOMEM; | |
876c9d3a MT |
567 | |
568 | buf_size = min(count, len - 1); | |
569 | if (copy_from_user(buf, userbuf, buf_size)) { | |
570 | res = -EFAULT; | |
571 | goto out_unlock; | |
572 | } | |
573 | priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16); | |
574 | res = count; | |
575 | out_unlock: | |
576 | free_page(addr); | |
577 | return res; | |
578 | } | |
579 | ||
10078321 | 580 | static ssize_t lbs_wrbbp_write(struct file *file, |
876c9d3a MT |
581 | const char __user *userbuf, |
582 | size_t count, loff_t *ppos) | |
583 | { | |
584 | ||
69f9032d | 585 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
586 | ssize_t res, buf_size; |
587 | u32 offset, value; | |
10078321 | 588 | struct lbs_offset_value offval; |
876c9d3a MT |
589 | unsigned long addr = get_zeroed_page(GFP_KERNEL); |
590 | char *buf = (char *)addr; | |
ad43f8bf KD |
591 | if (!buf) |
592 | return -ENOMEM; | |
876c9d3a MT |
593 | |
594 | buf_size = min(count, len - 1); | |
595 | if (copy_from_user(buf, userbuf, buf_size)) { | |
596 | res = -EFAULT; | |
597 | goto out_unlock; | |
598 | } | |
599 | res = sscanf(buf, "%x %x", &offset, &value); | |
600 | if (res != 2) { | |
601 | res = -EFAULT; | |
602 | goto out_unlock; | |
603 | } | |
604 | ||
605 | offval.offset = offset; | |
606 | offval.value = value; | |
10078321 | 607 | res = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
608 | CMD_BBP_REG_ACCESS, 1, |
609 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a MT |
610 | mdelay(10); |
611 | ||
c0bbd576 AK |
612 | if (!res) |
613 | res = count; | |
876c9d3a MT |
614 | out_unlock: |
615 | free_page(addr); | |
616 | return res; | |
617 | } | |
618 | ||
10078321 | 619 | static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, |
876c9d3a MT |
620 | size_t count, loff_t *ppos) |
621 | { | |
69f9032d | 622 | struct lbs_private *priv = file->private_data; |
10078321 | 623 | struct lbs_offset_value offval; |
876c9d3a MT |
624 | ssize_t pos = 0; |
625 | int ret; | |
626 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
627 | char *buf = (char *)addr; | |
ad43f8bf KD |
628 | if (!buf) |
629 | return -ENOMEM; | |
876c9d3a MT |
630 | |
631 | offval.offset = priv->rf_offset; | |
632 | offval.value = 0; | |
633 | ||
10078321 | 634 | ret = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
635 | CMD_RF_REG_ACCESS, 0, |
636 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a | 637 | mdelay(10); |
c0bbd576 AK |
638 | if (!ret) { |
639 | pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", | |
aa21c004 | 640 | priv->rf_offset, priv->offsetvalue.value); |
876c9d3a | 641 | |
c0bbd576 AK |
642 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); |
643 | } | |
876c9d3a MT |
644 | free_page(addr); |
645 | ||
646 | return ret; | |
647 | } | |
648 | ||
10078321 | 649 | static ssize_t lbs_rdrf_write(struct file *file, |
876c9d3a MT |
650 | const char __user *userbuf, |
651 | size_t count, loff_t *ppos) | |
652 | { | |
69f9032d | 653 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
654 | ssize_t res, buf_size; |
655 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
656 | char *buf = (char *)addr; | |
ad43f8bf KD |
657 | if (!buf) |
658 | return -ENOMEM; | |
876c9d3a MT |
659 | |
660 | buf_size = min(count, len - 1); | |
661 | if (copy_from_user(buf, userbuf, buf_size)) { | |
662 | res = -EFAULT; | |
663 | goto out_unlock; | |
664 | } | |
4101dec9 | 665 | priv->rf_offset = simple_strtoul(buf, NULL, 16); |
876c9d3a MT |
666 | res = count; |
667 | out_unlock: | |
668 | free_page(addr); | |
669 | return res; | |
670 | } | |
671 | ||
10078321 | 672 | static ssize_t lbs_wrrf_write(struct file *file, |
876c9d3a MT |
673 | const char __user *userbuf, |
674 | size_t count, loff_t *ppos) | |
675 | { | |
676 | ||
69f9032d | 677 | struct lbs_private *priv = file->private_data; |
876c9d3a MT |
678 | ssize_t res, buf_size; |
679 | u32 offset, value; | |
10078321 | 680 | struct lbs_offset_value offval; |
876c9d3a MT |
681 | unsigned long addr = get_zeroed_page(GFP_KERNEL); |
682 | char *buf = (char *)addr; | |
ad43f8bf KD |
683 | if (!buf) |
684 | return -ENOMEM; | |
876c9d3a MT |
685 | |
686 | buf_size = min(count, len - 1); | |
687 | if (copy_from_user(buf, userbuf, buf_size)) { | |
688 | res = -EFAULT; | |
689 | goto out_unlock; | |
690 | } | |
691 | res = sscanf(buf, "%x %x", &offset, &value); | |
692 | if (res != 2) { | |
693 | res = -EFAULT; | |
694 | goto out_unlock; | |
695 | } | |
696 | ||
697 | offval.offset = offset; | |
698 | offval.value = value; | |
10078321 | 699 | res = lbs_prepare_and_send_command(priv, |
0aef64d7 DW |
700 | CMD_RF_REG_ACCESS, 1, |
701 | CMD_OPTION_WAITFORRSP, 0, &offval); | |
876c9d3a MT |
702 | mdelay(10); |
703 | ||
c0bbd576 AK |
704 | if (!res) |
705 | res = count; | |
876c9d3a MT |
706 | out_unlock: |
707 | free_page(addr); | |
708 | return res; | |
709 | } | |
710 | ||
711 | #define FOPS(fread, fwrite) { \ | |
712 | .owner = THIS_MODULE, \ | |
713 | .open = open_file_generic, \ | |
714 | .read = (fread), \ | |
715 | .write = (fwrite), \ | |
716 | } | |
717 | ||
10078321 | 718 | struct lbs_debugfs_files { |
4101dec9 | 719 | const char *name; |
876c9d3a MT |
720 | int perm; |
721 | struct file_operations fops; | |
722 | }; | |
723 | ||
4101dec9 | 724 | static const struct lbs_debugfs_files debugfs_files[] = { |
10078321 HS |
725 | { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, |
726 | { "getscantable", 0444, FOPS(lbs_getscantable, | |
876c9d3a | 727 | write_file_dummy), }, |
10078321 HS |
728 | { "sleepparams", 0644, FOPS(lbs_sleepparams_read, |
729 | lbs_sleepparams_write), }, | |
876c9d3a MT |
730 | }; |
731 | ||
4101dec9 | 732 | static const struct lbs_debugfs_files debugfs_events_files[] = { |
10078321 HS |
733 | {"low_rssi", 0644, FOPS(lbs_lowrssi_read, |
734 | lbs_lowrssi_write), }, | |
735 | {"low_snr", 0644, FOPS(lbs_lowsnr_read, | |
736 | lbs_lowsnr_write), }, | |
737 | {"failure_count", 0644, FOPS(lbs_failcount_read, | |
738 | lbs_failcount_write), }, | |
739 | {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read, | |
740 | lbs_bcnmiss_write), }, | |
741 | {"high_rssi", 0644, FOPS(lbs_highrssi_read, | |
742 | lbs_highrssi_write), }, | |
743 | {"high_snr", 0644, FOPS(lbs_highsnr_read, | |
744 | lbs_highsnr_write), }, | |
876c9d3a MT |
745 | }; |
746 | ||
4101dec9 | 747 | static const struct lbs_debugfs_files debugfs_regs_files[] = { |
10078321 HS |
748 | {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), }, |
749 | {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), }, | |
750 | {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), }, | |
751 | {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), }, | |
752 | {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), }, | |
753 | {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), }, | |
876c9d3a MT |
754 | }; |
755 | ||
10078321 | 756 | void lbs_debugfs_init(void) |
876c9d3a | 757 | { |
10078321 HS |
758 | if (!lbs_dir) |
759 | lbs_dir = debugfs_create_dir("lbs_wireless", NULL); | |
876c9d3a MT |
760 | |
761 | return; | |
762 | } | |
763 | ||
10078321 | 764 | void lbs_debugfs_remove(void) |
876c9d3a | 765 | { |
10078321 HS |
766 | if (lbs_dir) |
767 | debugfs_remove(lbs_dir); | |
876c9d3a MT |
768 | return; |
769 | } | |
770 | ||
69f9032d | 771 | void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) |
876c9d3a MT |
772 | { |
773 | int i; | |
4101dec9 | 774 | const struct lbs_debugfs_files *files; |
10078321 | 775 | if (!lbs_dir) |
876c9d3a MT |
776 | goto exit; |
777 | ||
10078321 | 778 | priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir); |
876c9d3a MT |
779 | if (!priv->debugfs_dir) |
780 | goto exit; | |
781 | ||
782 | for (i=0; i<ARRAY_SIZE(debugfs_files); i++) { | |
783 | files = &debugfs_files[i]; | |
784 | priv->debugfs_files[i] = debugfs_create_file(files->name, | |
785 | files->perm, | |
786 | priv->debugfs_dir, | |
787 | priv, | |
788 | &files->fops); | |
789 | } | |
790 | ||
791 | priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); | |
792 | if (!priv->events_dir) | |
793 | goto exit; | |
794 | ||
795 | for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) { | |
796 | files = &debugfs_events_files[i]; | |
797 | priv->debugfs_events_files[i] = debugfs_create_file(files->name, | |
798 | files->perm, | |
799 | priv->events_dir, | |
800 | priv, | |
801 | &files->fops); | |
802 | } | |
803 | ||
804 | priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); | |
805 | if (!priv->regs_dir) | |
806 | goto exit; | |
807 | ||
808 | for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) { | |
809 | files = &debugfs_regs_files[i]; | |
810 | priv->debugfs_regs_files[i] = debugfs_create_file(files->name, | |
811 | files->perm, | |
812 | priv->regs_dir, | |
813 | priv, | |
814 | &files->fops); | |
815 | } | |
816 | ||
817 | #ifdef PROC_DEBUG | |
e98a88dd | 818 | lbs_debug_init(priv); |
876c9d3a MT |
819 | #endif |
820 | exit: | |
821 | return; | |
822 | } | |
823 | ||
69f9032d | 824 | void lbs_debugfs_remove_one(struct lbs_private *priv) |
876c9d3a MT |
825 | { |
826 | int i; | |
827 | ||
828 | for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) | |
829 | debugfs_remove(priv->debugfs_regs_files[i]); | |
830 | ||
831 | debugfs_remove(priv->regs_dir); | |
832 | ||
0b7db956 | 833 | for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++) |
876c9d3a MT |
834 | debugfs_remove(priv->debugfs_events_files[i]); |
835 | ||
836 | debugfs_remove(priv->events_dir); | |
837 | #ifdef PROC_DEBUG | |
838 | debugfs_remove(priv->debugfs_debug); | |
839 | #endif | |
840 | for(i=0; i<ARRAY_SIZE(debugfs_files); i++) | |
841 | debugfs_remove(priv->debugfs_files[i]); | |
0b7db956 | 842 | debugfs_remove(priv->debugfs_dir); |
876c9d3a MT |
843 | } |
844 | ||
46868202 HS |
845 | |
846 | ||
876c9d3a MT |
847 | /* debug entry */ |
848 | ||
46868202 HS |
849 | #ifdef PROC_DEBUG |
850 | ||
aa21c004 DW |
851 | #define item_size(n) (FIELD_SIZEOF(struct lbs_private, n)) |
852 | #define item_addr(n) (offsetof(struct lbs_private, n)) | |
876c9d3a | 853 | |
46868202 | 854 | |
876c9d3a MT |
855 | struct debug_data { |
856 | char name[32]; | |
857 | u32 size; | |
4269e2ad | 858 | size_t addr; |
876c9d3a MT |
859 | }; |
860 | ||
aa21c004 | 861 | /* To debug any member of struct lbs_private, simply add one line here. |
876c9d3a MT |
862 | */ |
863 | static struct debug_data items[] = { | |
876c9d3a MT |
864 | {"psmode", item_size(psmode), item_addr(psmode)}, |
865 | {"psstate", item_size(psstate), item_addr(psstate)}, | |
866 | }; | |
867 | ||
d2f11e09 | 868 | static int num_of_items = ARRAY_SIZE(items); |
876c9d3a MT |
869 | |
870 | /** | |
871 | * @brief proc read function | |
872 | * | |
873 | * @param page pointer to buffer | |
874 | * @param s read data starting position | |
875 | * @param off offset | |
876 | * @param cnt counter | |
877 | * @param eof end of file flag | |
878 | * @param data data to output | |
879 | * @return number of output data | |
880 | */ | |
10078321 | 881 | static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, |
876c9d3a MT |
882 | size_t count, loff_t *ppos) |
883 | { | |
884 | int val = 0; | |
885 | size_t pos = 0; | |
886 | ssize_t res; | |
887 | char *p; | |
888 | int i; | |
889 | struct debug_data *d; | |
890 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | |
891 | char *buf = (char *)addr; | |
ad43f8bf KD |
892 | if (!buf) |
893 | return -ENOMEM; | |
876c9d3a MT |
894 | |
895 | p = buf; | |
896 | ||
897 | d = (struct debug_data *)file->private_data; | |
898 | ||
899 | for (i = 0; i < num_of_items; i++) { | |
900 | if (d[i].size == 1) | |
901 | val = *((u8 *) d[i].addr); | |
902 | else if (d[i].size == 2) | |
903 | val = *((u16 *) d[i].addr); | |
904 | else if (d[i].size == 4) | |
905 | val = *((u32 *) d[i].addr); | |
4269e2ad DW |
906 | else if (d[i].size == 8) |
907 | val = *((u64 *) d[i].addr); | |
876c9d3a MT |
908 | |
909 | pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); | |
910 | } | |
911 | ||
912 | res = simple_read_from_buffer(userbuf, count, ppos, p, pos); | |
913 | ||
914 | free_page(addr); | |
915 | return res; | |
916 | } | |
917 | ||
918 | /** | |
919 | * @brief proc write function | |
920 | * | |
921 | * @param f file pointer | |
922 | * @param buf pointer to data buffer | |
923 | * @param cnt data number to write | |
924 | * @param data data to write | |
925 | * @return number of data | |
926 | */ | |
10078321 | 927 | static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, |
876c9d3a MT |
928 | size_t cnt, loff_t *ppos) |
929 | { | |
930 | int r, i; | |
931 | char *pdata; | |
932 | char *p; | |
933 | char *p0; | |
934 | char *p1; | |
935 | char *p2; | |
936 | struct debug_data *d = (struct debug_data *)f->private_data; | |
937 | ||
655b4d16 | 938 | pdata = kmalloc(cnt, GFP_KERNEL); |
876c9d3a MT |
939 | if (pdata == NULL) |
940 | return 0; | |
941 | ||
942 | if (copy_from_user(pdata, buf, cnt)) { | |
9012b28a | 943 | lbs_deb_debugfs("Copy from user failed\n"); |
876c9d3a MT |
944 | kfree(pdata); |
945 | return 0; | |
946 | } | |
947 | ||
948 | p0 = pdata; | |
949 | for (i = 0; i < num_of_items; i++) { | |
950 | do { | |
951 | p = strstr(p0, d[i].name); | |
952 | if (p == NULL) | |
953 | break; | |
954 | p1 = strchr(p, '\n'); | |
955 | if (p1 == NULL) | |
956 | break; | |
957 | p0 = p1++; | |
958 | p2 = strchr(p, '='); | |
959 | if (!p2) | |
960 | break; | |
961 | p2++; | |
d2f11e09 | 962 | r = simple_strtoul(p2, NULL, 0); |
876c9d3a MT |
963 | if (d[i].size == 1) |
964 | *((u8 *) d[i].addr) = (u8) r; | |
965 | else if (d[i].size == 2) | |
966 | *((u16 *) d[i].addr) = (u16) r; | |
967 | else if (d[i].size == 4) | |
968 | *((u32 *) d[i].addr) = (u32) r; | |
4269e2ad DW |
969 | else if (d[i].size == 8) |
970 | *((u64 *) d[i].addr) = (u64) r; | |
876c9d3a MT |
971 | break; |
972 | } while (1); | |
973 | } | |
974 | kfree(pdata); | |
975 | ||
4269e2ad | 976 | return (ssize_t)cnt; |
876c9d3a MT |
977 | } |
978 | ||
4101dec9 | 979 | static const struct file_operations lbs_debug_fops = { |
876c9d3a MT |
980 | .owner = THIS_MODULE, |
981 | .open = open_file_generic, | |
10078321 HS |
982 | .write = lbs_debugfs_write, |
983 | .read = lbs_debugfs_read, | |
876c9d3a MT |
984 | }; |
985 | ||
986 | /** | |
987 | * @brief create debug proc file | |
988 | * | |
69f9032d | 989 | * @param priv pointer struct lbs_private |
876c9d3a MT |
990 | * @param dev pointer net_device |
991 | * @return N/A | |
992 | */ | |
e98a88dd | 993 | static void lbs_debug_init(struct lbs_private *priv) |
876c9d3a MT |
994 | { |
995 | int i; | |
996 | ||
997 | if (!priv->debugfs_dir) | |
998 | return; | |
999 | ||
1000 | for (i = 0; i < num_of_items; i++) | |
aa21c004 | 1001 | items[i].addr += (size_t) priv; |
876c9d3a MT |
1002 | |
1003 | priv->debugfs_debug = debugfs_create_file("debug", 0644, | |
1004 | priv->debugfs_dir, &items[0], | |
10078321 | 1005 | &lbs_debug_fops); |
876c9d3a | 1006 | } |
46868202 | 1007 | #endif |