18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * uvc_debugfs.c -- USB Video Class driver - Debugging support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 68c2ecf20Sopenharmony_ci * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/usb.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "uvcvideo.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 178c2ecf20Sopenharmony_ci * Statistics 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define UVC_DEBUGFS_BUF_SIZE 1024 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct uvc_debugfs_buffer { 238c2ecf20Sopenharmony_ci size_t count; 248c2ecf20Sopenharmony_ci char data[UVC_DEBUGFS_BUF_SIZE]; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int uvc_debugfs_stats_open(struct inode *inode, struct file *file) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct uvc_streaming *stream = inode->i_private; 308c2ecf20Sopenharmony_ci struct uvc_debugfs_buffer *buf; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci buf = kmalloc(sizeof(*buf), GFP_KERNEL); 338c2ecf20Sopenharmony_ci if (buf == NULL) 348c2ecf20Sopenharmony_ci return -ENOMEM; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data)); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci file->private_data = buf; 398c2ecf20Sopenharmony_ci return 0; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf, 438c2ecf20Sopenharmony_ci size_t nbytes, loff_t *ppos) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct uvc_debugfs_buffer *buf = file->private_data; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data, 488c2ecf20Sopenharmony_ci buf->count); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int uvc_debugfs_stats_release(struct inode *inode, struct file *file) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci kfree(file->private_data); 548c2ecf20Sopenharmony_ci file->private_data = NULL; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const struct file_operations uvc_debugfs_stats_fops = { 608c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 618c2ecf20Sopenharmony_ci .open = uvc_debugfs_stats_open, 628c2ecf20Sopenharmony_ci .llseek = no_llseek, 638c2ecf20Sopenharmony_ci .read = uvc_debugfs_stats_read, 648c2ecf20Sopenharmony_ci .release = uvc_debugfs_stats_release, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 688c2ecf20Sopenharmony_ci * Global and stream initialization/cleanup 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic struct dentry *uvc_debugfs_root_dir; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_civoid uvc_debugfs_init_stream(struct uvc_streaming *stream) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct usb_device *udev = stream->dev->udev; 768c2ecf20Sopenharmony_ci char dir_name[33]; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (uvc_debugfs_root_dir == NULL) 798c2ecf20Sopenharmony_ci return; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci snprintf(dir_name, sizeof(dir_name), "%u-%u-%u", udev->bus->busnum, 828c2ecf20Sopenharmony_ci udev->devnum, stream->intfnum); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci stream->debugfs_dir = debugfs_create_dir(dir_name, 858c2ecf20Sopenharmony_ci uvc_debugfs_root_dir); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci debugfs_create_file("stats", 0444, stream->debugfs_dir, stream, 888c2ecf20Sopenharmony_ci &uvc_debugfs_stats_fops); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_civoid uvc_debugfs_cleanup_stream(struct uvc_streaming *stream) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci debugfs_remove_recursive(stream->debugfs_dir); 948c2ecf20Sopenharmony_ci stream->debugfs_dir = NULL; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid uvc_debugfs_init(void) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci uvc_debugfs_root_dir = debugfs_create_dir("uvcvideo", usb_debug_root); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_civoid uvc_debugfs_cleanup(void) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci debugfs_remove_recursive(uvc_debugfs_root_dir); 1058c2ecf20Sopenharmony_ci} 106