Bluetooth: Move BR/EDR debugfs file creation into hci_debugfs.c
[deliverable/linux.git] / net / bluetooth / hci_debugfs.c
CommitLineData
60c5f5fb
MH
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3
4 Copyright (C) 2014 Intel Corporation
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation;
9
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
11 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
13 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
14 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
20 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
21 SOFTWARE IS DISCLAIMED.
22*/
23
24#include <linux/debugfs.h>
25
26#include <net/bluetooth/bluetooth.h>
27#include <net/bluetooth/hci_core.h>
28
29#include "hci_debugfs.h"
30
40ce72b1
MH
31static int features_show(struct seq_file *f, void *ptr)
32{
33 struct hci_dev *hdev = f->private;
34 u8 p;
35
36 hci_dev_lock(hdev);
37 for (p = 0; p < HCI_MAX_PAGES && p <= hdev->max_page; p++) {
38 seq_printf(f, "%2u: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
39 "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", p,
40 hdev->features[p][0], hdev->features[p][1],
41 hdev->features[p][2], hdev->features[p][3],
42 hdev->features[p][4], hdev->features[p][5],
43 hdev->features[p][6], hdev->features[p][7]);
44 }
45 if (lmp_le_capable(hdev))
46 seq_printf(f, "LE: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x "
47 "0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n",
48 hdev->le_features[0], hdev->le_features[1],
49 hdev->le_features[2], hdev->le_features[3],
50 hdev->le_features[4], hdev->le_features[5],
51 hdev->le_features[6], hdev->le_features[7]);
52 hci_dev_unlock(hdev);
53
54 return 0;
55}
56
57static int features_open(struct inode *inode, struct file *file)
58{
59 return single_open(file, features_show, inode->i_private);
60}
61
62static const struct file_operations features_fops = {
63 .open = features_open,
64 .read = seq_read,
65 .llseek = seq_lseek,
66 .release = single_release,
67};
68
69static int device_list_show(struct seq_file *f, void *ptr)
70{
71 struct hci_dev *hdev = f->private;
72 struct hci_conn_params *p;
73 struct bdaddr_list *b;
74
75 hci_dev_lock(hdev);
76 list_for_each_entry(b, &hdev->whitelist, list)
77 seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
78 list_for_each_entry(p, &hdev->le_conn_params, list) {
79 seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type,
80 p->auto_connect);
81 }
82 hci_dev_unlock(hdev);
83
84 return 0;
85}
86
87static int device_list_open(struct inode *inode, struct file *file)
88{
89 return single_open(file, device_list_show, inode->i_private);
90}
91
92static const struct file_operations device_list_fops = {
93 .open = device_list_open,
94 .read = seq_read,
95 .llseek = seq_lseek,
96 .release = single_release,
97};
98
99static int blacklist_show(struct seq_file *f, void *p)
100{
101 struct hci_dev *hdev = f->private;
102 struct bdaddr_list *b;
103
104 hci_dev_lock(hdev);
105 list_for_each_entry(b, &hdev->blacklist, list)
106 seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
107 hci_dev_unlock(hdev);
108
109 return 0;
110}
111
112static int blacklist_open(struct inode *inode, struct file *file)
113{
114 return single_open(file, blacklist_show, inode->i_private);
115}
116
117static const struct file_operations blacklist_fops = {
118 .open = blacklist_open,
119 .read = seq_read,
120 .llseek = seq_lseek,
121 .release = single_release,
122};
123
124static int uuids_show(struct seq_file *f, void *p)
125{
126 struct hci_dev *hdev = f->private;
127 struct bt_uuid *uuid;
128
129 hci_dev_lock(hdev);
130 list_for_each_entry(uuid, &hdev->uuids, list) {
131 u8 i, val[16];
132
133 /* The Bluetooth UUID values are stored in big endian,
134 * but with reversed byte order. So convert them into
135 * the right order for the %pUb modifier.
136 */
137 for (i = 0; i < 16; i++)
138 val[i] = uuid->uuid[15 - i];
139
140 seq_printf(f, "%pUb\n", val);
141 }
142 hci_dev_unlock(hdev);
143
144 return 0;
145}
146
147static int uuids_open(struct inode *inode, struct file *file)
148{
149 return single_open(file, uuids_show, inode->i_private);
150}
151
152static const struct file_operations uuids_fops = {
153 .open = uuids_open,
154 .read = seq_read,
155 .llseek = seq_lseek,
156 .release = single_release,
157};
158
159static int conn_info_min_age_set(void *data, u64 val)
160{
161 struct hci_dev *hdev = data;
162
163 if (val == 0 || val > hdev->conn_info_max_age)
164 return -EINVAL;
165
166 hci_dev_lock(hdev);
167 hdev->conn_info_min_age = val;
168 hci_dev_unlock(hdev);
169
170 return 0;
171}
172
173static int conn_info_min_age_get(void *data, u64 *val)
174{
175 struct hci_dev *hdev = data;
176
177 hci_dev_lock(hdev);
178 *val = hdev->conn_info_min_age;
179 hci_dev_unlock(hdev);
180
181 return 0;
182}
183
184DEFINE_SIMPLE_ATTRIBUTE(conn_info_min_age_fops, conn_info_min_age_get,
185 conn_info_min_age_set, "%llu\n");
186
187static int conn_info_max_age_set(void *data, u64 val)
188{
189 struct hci_dev *hdev = data;
190
191 if (val == 0 || val < hdev->conn_info_min_age)
192 return -EINVAL;
193
194 hci_dev_lock(hdev);
195 hdev->conn_info_max_age = val;
196 hci_dev_unlock(hdev);
197
198 return 0;
199}
200
201static int conn_info_max_age_get(void *data, u64 *val)
202{
203 struct hci_dev *hdev = data;
204
205 hci_dev_lock(hdev);
206 *val = hdev->conn_info_max_age;
207 hci_dev_unlock(hdev);
208
209 return 0;
210}
211
212DEFINE_SIMPLE_ATTRIBUTE(conn_info_max_age_fops, conn_info_max_age_get,
213 conn_info_max_age_set, "%llu\n");
214
60c5f5fb
MH
215void hci_debugfs_create_common(struct hci_dev *hdev)
216{
40ce72b1
MH
217 debugfs_create_file("features", 0444, hdev->debugfs, hdev,
218 &features_fops);
219 debugfs_create_u16("manufacturer", 0444, hdev->debugfs,
220 &hdev->manufacturer);
221 debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver);
222 debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev);
223 debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
224 &device_list_fops);
225 debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev,
226 &blacklist_fops);
227 debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
228
229 debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev,
230 &conn_info_min_age_fops);
231 debugfs_create_file("conn_info_max_age", 0644, hdev->debugfs, hdev,
232 &conn_info_max_age_fops);
60c5f5fb
MH
233}
234
71c3b60e
MH
235static int inquiry_cache_show(struct seq_file *f, void *p)
236{
237 struct hci_dev *hdev = f->private;
238 struct discovery_state *cache = &hdev->discovery;
239 struct inquiry_entry *e;
240
241 hci_dev_lock(hdev);
242
243 list_for_each_entry(e, &cache->all, all) {
244 struct inquiry_data *data = &e->data;
245 seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
246 &data->bdaddr,
247 data->pscan_rep_mode, data->pscan_period_mode,
248 data->pscan_mode, data->dev_class[2],
249 data->dev_class[1], data->dev_class[0],
250 __le16_to_cpu(data->clock_offset),
251 data->rssi, data->ssp_mode, e->timestamp);
252 }
253
254 hci_dev_unlock(hdev);
255
256 return 0;
257}
258
259static int inquiry_cache_open(struct inode *inode, struct file *file)
260{
261 return single_open(file, inquiry_cache_show, inode->i_private);
262}
263
264static const struct file_operations inquiry_cache_fops = {
265 .open = inquiry_cache_open,
266 .read = seq_read,
267 .llseek = seq_lseek,
268 .release = single_release,
269};
270
271static int link_keys_show(struct seq_file *f, void *ptr)
272{
273 struct hci_dev *hdev = f->private;
274 struct link_key *key;
275
276 rcu_read_lock();
277 list_for_each_entry_rcu(key, &hdev->link_keys, list)
278 seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type,
279 HCI_LINK_KEY_SIZE, key->val, key->pin_len);
280 rcu_read_unlock();
281
282 return 0;
283}
284
285static int link_keys_open(struct inode *inode, struct file *file)
286{
287 return single_open(file, link_keys_show, inode->i_private);
288}
289
290static const struct file_operations link_keys_fops = {
291 .open = link_keys_open,
292 .read = seq_read,
293 .llseek = seq_lseek,
294 .release = single_release,
295};
296
297static int dev_class_show(struct seq_file *f, void *ptr)
298{
299 struct hci_dev *hdev = f->private;
300
301 hci_dev_lock(hdev);
302 seq_printf(f, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
303 hdev->dev_class[1], hdev->dev_class[0]);
304 hci_dev_unlock(hdev);
305
306 return 0;
307}
308
309static int dev_class_open(struct inode *inode, struct file *file)
310{
311 return single_open(file, dev_class_show, inode->i_private);
312}
313
314static const struct file_operations dev_class_fops = {
315 .open = dev_class_open,
316 .read = seq_read,
317 .llseek = seq_lseek,
318 .release = single_release,
319};
320
321static int voice_setting_get(void *data, u64 *val)
322{
323 struct hci_dev *hdev = data;
324
325 hci_dev_lock(hdev);
326 *val = hdev->voice_setting;
327 hci_dev_unlock(hdev);
328
329 return 0;
330}
331
332DEFINE_SIMPLE_ATTRIBUTE(voice_setting_fops, voice_setting_get,
333 NULL, "0x%4.4llx\n");
334
335static int auto_accept_delay_set(void *data, u64 val)
336{
337 struct hci_dev *hdev = data;
338
339 hci_dev_lock(hdev);
340 hdev->auto_accept_delay = val;
341 hci_dev_unlock(hdev);
342
343 return 0;
344}
345
346static int auto_accept_delay_get(void *data, u64 *val)
347{
348 struct hci_dev *hdev = data;
349
350 hci_dev_lock(hdev);
351 *val = hdev->auto_accept_delay;
352 hci_dev_unlock(hdev);
353
354 return 0;
355}
356
357DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
358 auto_accept_delay_set, "%llu\n");
359
360static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
361 size_t count, loff_t *ppos)
362{
363 struct hci_dev *hdev = file->private_data;
364 char buf[3];
365
366 buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N';
367 buf[1] = '\n';
368 buf[2] = '\0';
369 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
370}
371
372static const struct file_operations sc_only_mode_fops = {
373 .open = simple_open,
374 .read = sc_only_mode_read,
375 .llseek = default_llseek,
376};
377
378static ssize_t force_sc_support_read(struct file *file, char __user *user_buf,
379 size_t count, loff_t *ppos)
380{
381 struct hci_dev *hdev = file->private_data;
382 char buf[3];
383
384 buf[0] = test_bit(HCI_FORCE_SC, &hdev->dbg_flags) ? 'Y': 'N';
385 buf[1] = '\n';
386 buf[2] = '\0';
387 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
388}
389
390static ssize_t force_sc_support_write(struct file *file,
391 const char __user *user_buf,
392 size_t count, loff_t *ppos)
393{
394 struct hci_dev *hdev = file->private_data;
395 char buf[32];
396 size_t buf_size = min(count, (sizeof(buf)-1));
397 bool enable;
398
399 if (test_bit(HCI_UP, &hdev->flags))
400 return -EBUSY;
401
402 if (copy_from_user(buf, user_buf, buf_size))
403 return -EFAULT;
404
405 buf[buf_size] = '\0';
406 if (strtobool(buf, &enable))
407 return -EINVAL;
408
409 if (enable == test_bit(HCI_FORCE_SC, &hdev->dbg_flags))
410 return -EALREADY;
411
412 change_bit(HCI_FORCE_SC, &hdev->dbg_flags);
413
414 return count;
415}
416
417static const struct file_operations force_sc_support_fops = {
418 .open = simple_open,
419 .read = force_sc_support_read,
420 .write = force_sc_support_write,
421 .llseek = default_llseek,
422};
423
424static ssize_t force_lesc_support_read(struct file *file,
425 char __user *user_buf,
426 size_t count, loff_t *ppos)
427{
428 struct hci_dev *hdev = file->private_data;
429 char buf[3];
430
431 buf[0] = test_bit(HCI_FORCE_LESC, &hdev->dbg_flags) ? 'Y': 'N';
432 buf[1] = '\n';
433 buf[2] = '\0';
434 return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
435}
436
437static ssize_t force_lesc_support_write(struct file *file,
438 const char __user *user_buf,
439 size_t count, loff_t *ppos)
440{
441 struct hci_dev *hdev = file->private_data;
442 char buf[32];
443 size_t buf_size = min(count, (sizeof(buf)-1));
444 bool enable;
445
446 if (copy_from_user(buf, user_buf, buf_size))
447 return -EFAULT;
448
449 buf[buf_size] = '\0';
450 if (strtobool(buf, &enable))
451 return -EINVAL;
452
453 if (enable == test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
454 return -EALREADY;
455
456 change_bit(HCI_FORCE_LESC, &hdev->dbg_flags);
457
458 return count;
459}
460
461static const struct file_operations force_lesc_support_fops = {
462 .open = simple_open,
463 .read = force_lesc_support_read,
464 .write = force_lesc_support_write,
465 .llseek = default_llseek,
466};
467
468static int idle_timeout_set(void *data, u64 val)
469{
470 struct hci_dev *hdev = data;
471
472 if (val != 0 && (val < 500 || val > 3600000))
473 return -EINVAL;
474
475 hci_dev_lock(hdev);
476 hdev->idle_timeout = val;
477 hci_dev_unlock(hdev);
478
479 return 0;
480}
481
482static int idle_timeout_get(void *data, u64 *val)
483{
484 struct hci_dev *hdev = data;
485
486 hci_dev_lock(hdev);
487 *val = hdev->idle_timeout;
488 hci_dev_unlock(hdev);
489
490 return 0;
491}
492
493DEFINE_SIMPLE_ATTRIBUTE(idle_timeout_fops, idle_timeout_get,
494 idle_timeout_set, "%llu\n");
495
496static int sniff_min_interval_set(void *data, u64 val)
497{
498 struct hci_dev *hdev = data;
499
500 if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
501 return -EINVAL;
502
503 hci_dev_lock(hdev);
504 hdev->sniff_min_interval = val;
505 hci_dev_unlock(hdev);
506
507 return 0;
508}
509
510static int sniff_min_interval_get(void *data, u64 *val)
511{
512 struct hci_dev *hdev = data;
513
514 hci_dev_lock(hdev);
515 *val = hdev->sniff_min_interval;
516 hci_dev_unlock(hdev);
517
518 return 0;
519}
520
521DEFINE_SIMPLE_ATTRIBUTE(sniff_min_interval_fops, sniff_min_interval_get,
522 sniff_min_interval_set, "%llu\n");
523
524static int sniff_max_interval_set(void *data, u64 val)
525{
526 struct hci_dev *hdev = data;
527
528 if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
529 return -EINVAL;
530
531 hci_dev_lock(hdev);
532 hdev->sniff_max_interval = val;
533 hci_dev_unlock(hdev);
534
535 return 0;
536}
537
538static int sniff_max_interval_get(void *data, u64 *val)
539{
540 struct hci_dev *hdev = data;
541
542 hci_dev_lock(hdev);
543 *val = hdev->sniff_max_interval;
544 hci_dev_unlock(hdev);
545
546 return 0;
547}
548
549DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get,
550 sniff_max_interval_set, "%llu\n");
551
60c5f5fb
MH
552void hci_debugfs_create_bredr(struct hci_dev *hdev)
553{
71c3b60e
MH
554 debugfs_create_file("inquiry_cache", 0444, hdev->debugfs, hdev,
555 &inquiry_cache_fops);
556 debugfs_create_file("link_keys", 0400, hdev->debugfs, hdev,
557 &link_keys_fops);
558 debugfs_create_file("dev_class", 0444, hdev->debugfs, hdev,
559 &dev_class_fops);
560 debugfs_create_file("voice_setting", 0444, hdev->debugfs, hdev,
561 &voice_setting_fops);
562
563 if (lmp_ssp_capable(hdev)) {
564 debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs,
565 hdev, &auto_accept_delay_fops);
566 debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
567 hdev, &sc_only_mode_fops);
568
569 debugfs_create_file("force_sc_support", 0644, hdev->debugfs,
570 hdev, &force_sc_support_fops);
571
572 if (lmp_le_capable(hdev))
573 debugfs_create_file("force_lesc_support", 0644,
574 hdev->debugfs, hdev,
575 &force_lesc_support_fops);
576 }
577
578 if (lmp_sniff_capable(hdev)) {
579 debugfs_create_file("idle_timeout", 0644, hdev->debugfs,
580 hdev, &idle_timeout_fops);
581 debugfs_create_file("sniff_min_interval", 0644, hdev->debugfs,
582 hdev, &sniff_min_interval_fops);
583 debugfs_create_file("sniff_max_interval", 0644, hdev->debugfs,
584 hdev, &sniff_max_interval_fops);
585 }
60c5f5fb
MH
586}
587
588void hci_debugfs_create_le(struct hci_dev *hdev)
589{
590}
This page took 0.060492 seconds and 5 git commands to generate.