1edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher/* 2edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * uvc_debugfs.c -- USB Video Class driver - Debugging support 3edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * 4edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * Copyright (C) 2011 5edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 6edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * 7edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * This program is free software; you can redistribute it and/or modify 8edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * it under the terms of the GNU General Public License as published by 9edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * the Free Software Foundation; either version 2 of the License, or 10edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * (at your option) any later version. 11edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * 12edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher */ 13edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 14edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher#include <linux/module.h> 15edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher#include <linux/debugfs.h> 16edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher#include <linux/slab.h> 17edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher#include <linux/usb.h> 18edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 19edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher#include "uvcvideo.h" 20edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 21edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher/* ----------------------------------------------------------------------------- 227bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher * Statistics 237bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher */ 247bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 257bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher#define UVC_DEBUGFS_BUF_SIZE 1024 267bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 277bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisherstruct uvc_debugfs_buffer { 287bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher size_t count; 297bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher char data[UVC_DEBUGFS_BUF_SIZE]; 307bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher}; 317bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 327bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisherstatic int uvc_debugfs_stats_open(struct inode *inode, struct file *file) 337bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher{ 347bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher struct uvc_streaming *stream = inode->i_private; 357bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher struct uvc_debugfs_buffer *buf; 367bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 377bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher buf = kmalloc(sizeof(*buf), GFP_KERNEL); 387bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher if (buf == NULL) 397bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher return -ENOMEM; 407bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 417bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data)); 427bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 437bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher file->private_data = buf; 447bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher return 0; 457bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher} 467bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 477bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisherstatic ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf, 487bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher size_t nbytes, loff_t *ppos) 497bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher{ 507bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher struct uvc_debugfs_buffer *buf = file->private_data; 517bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 527bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data, 537bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher buf->count); 547bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher} 557bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 567bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisherstatic int uvc_debugfs_stats_release(struct inode *inode, struct file *file) 577bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher{ 587bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher kfree(file->private_data); 597bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher file->private_data = NULL; 607bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 617bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher return 0; 627bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher} 637bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 647bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisherstatic const struct file_operations uvc_debugfs_stats_fops = { 657bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher .owner = THIS_MODULE, 667bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher .open = uvc_debugfs_stats_open, 677bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher .llseek = no_llseek, 687bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher .read = uvc_debugfs_stats_read, 697bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher .release = uvc_debugfs_stats_release, 707bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher}; 717bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 727bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher/* ----------------------------------------------------------------------------- 73edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher * Global and stream initialization/cleanup 74edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher */ 75edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 76edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisherstatic struct dentry *uvc_debugfs_root_dir; 77edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 78edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisherint uvc_debugfs_init_stream(struct uvc_streaming *stream) 79edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher{ 80edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher struct usb_device *udev = stream->dev->udev; 81edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher struct dentry *dent; 82edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher char dir_name[32]; 83edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 84edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher if (uvc_debugfs_root_dir == NULL) 85edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return -ENODEV; 86edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 87edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); 88edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 89edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); 90edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher if (IS_ERR_OR_NULL(dent)) { 917bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher uvc_printk(KERN_INFO, "Unable to create debugfs %s " 927bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher "directory.\n", dir_name); 93edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return -ENODEV; 94edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher } 95edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 96edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher stream->debugfs_dir = dent; 97edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 987bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher dent = debugfs_create_file("stats", 0444, stream->debugfs_dir, 997bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher stream, &uvc_debugfs_stats_fops); 1007bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher if (IS_ERR_OR_NULL(dent)) { 1017bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n"); 1027bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher uvc_debugfs_cleanup_stream(stream); 1037bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher return -ENODEV; 1047bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher } 1057bc5edb00bbd02449576289a50d2900f58e7187aAlexey Fisher 106edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return 0; 107edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher} 108edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 109edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fishervoid uvc_debugfs_cleanup_stream(struct uvc_streaming *stream) 110edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher{ 111edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher if (stream->debugfs_dir == NULL) 112edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return; 113edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 114edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher debugfs_remove_recursive(stream->debugfs_dir); 115edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher stream->debugfs_dir = NULL; 116edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher} 117edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 118edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisherint uvc_debugfs_init(void) 119edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher{ 120edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher struct dentry *dir; 121edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 122edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher dir = debugfs_create_dir("uvcvideo", usb_debug_root); 123edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher if (IS_ERR_OR_NULL(dir)) { 124edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher uvc_printk(KERN_INFO, "Unable to create debugfs directory\n"); 125edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return -ENODATA; 126edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher } 127edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 128edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher uvc_debugfs_root_dir = dir; 129edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher return 0; 130edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher} 131edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher 132edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fishervoid uvc_debugfs_cleanup(void) 133edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher{ 134edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher if (uvc_debugfs_root_dir != NULL) 135edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher debugfs_remove_recursive(uvc_debugfs_root_dir); 136edbaa39842793fc4ac6603b277f2ad76f2057a45Alexey Fisher} 137