12504ba9fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 20c0d06caSMauro Carvalho Chehab /* 30c0d06caSMauro Carvalho Chehab * 40c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 Mike Isely <isely@pobox.com> 50c0d06caSMauro Carvalho Chehab */ 60c0d06caSMauro Carvalho Chehab 70c0d06caSMauro Carvalho Chehab #include <linux/string.h> 80c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 90c0d06caSMauro Carvalho Chehab #include "pvrusb2-sysfs.h" 100c0d06caSMauro Carvalho Chehab #include "pvrusb2-hdw.h" 110c0d06caSMauro Carvalho Chehab #include "pvrusb2-debug.h" 120c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 130c0d06caSMauro Carvalho Chehab #include "pvrusb2-debugifc.h" 140c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 150c0d06caSMauro Carvalho Chehab 160c0d06caSMauro Carvalho Chehab #define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__) 170c0d06caSMauro Carvalho Chehab 180c0d06caSMauro Carvalho Chehab struct pvr2_sysfs { 190c0d06caSMauro Carvalho Chehab struct pvr2_channel channel; 200c0d06caSMauro Carvalho Chehab struct device *class_dev; 210c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 220c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_debugifc *debugifc; 230c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 240c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *item_first; 250c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *item_last; 260c0d06caSMauro Carvalho Chehab struct device_attribute attr_v4l_minor_number; 270c0d06caSMauro Carvalho Chehab struct device_attribute attr_v4l_radio_minor_number; 280c0d06caSMauro Carvalho Chehab struct device_attribute attr_unit_number; 290c0d06caSMauro Carvalho Chehab struct device_attribute attr_bus_info; 300c0d06caSMauro Carvalho Chehab struct device_attribute attr_hdw_name; 310c0d06caSMauro Carvalho Chehab struct device_attribute attr_hdw_desc; 320c0d06caSMauro Carvalho Chehab int v4l_minor_number_created_ok; 330c0d06caSMauro Carvalho Chehab int v4l_radio_minor_number_created_ok; 340c0d06caSMauro Carvalho Chehab int unit_number_created_ok; 350c0d06caSMauro Carvalho Chehab int bus_info_created_ok; 360c0d06caSMauro Carvalho Chehab int hdw_name_created_ok; 370c0d06caSMauro Carvalho Chehab int hdw_desc_created_ok; 380c0d06caSMauro Carvalho Chehab }; 390c0d06caSMauro Carvalho Chehab 400c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 410c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_debugifc { 420c0d06caSMauro Carvalho Chehab struct device_attribute attr_debugcmd; 430c0d06caSMauro Carvalho Chehab struct device_attribute attr_debuginfo; 440c0d06caSMauro Carvalho Chehab int debugcmd_created_ok; 450c0d06caSMauro Carvalho Chehab int debuginfo_created_ok; 460c0d06caSMauro Carvalho Chehab }; 470c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 480c0d06caSMauro Carvalho Chehab 490c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item { 500c0d06caSMauro Carvalho Chehab struct device_attribute attr_name; 510c0d06caSMauro Carvalho Chehab struct device_attribute attr_type; 520c0d06caSMauro Carvalho Chehab struct device_attribute attr_min; 530c0d06caSMauro Carvalho Chehab struct device_attribute attr_max; 540c0d06caSMauro Carvalho Chehab struct device_attribute attr_def; 550c0d06caSMauro Carvalho Chehab struct device_attribute attr_enum; 560c0d06caSMauro Carvalho Chehab struct device_attribute attr_bits; 570c0d06caSMauro Carvalho Chehab struct device_attribute attr_val; 580c0d06caSMauro Carvalho Chehab struct device_attribute attr_custom; 590c0d06caSMauro Carvalho Chehab struct pvr2_ctrl *cptr; 600c0d06caSMauro Carvalho Chehab int ctl_id; 610c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *chptr; 620c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *item_next; 630c0d06caSMauro Carvalho Chehab struct attribute *attr_gen[8]; 640c0d06caSMauro Carvalho Chehab struct attribute_group grp; 650c0d06caSMauro Carvalho Chehab int created_ok; 660c0d06caSMauro Carvalho Chehab char name[80]; 670c0d06caSMauro Carvalho Chehab }; 680c0d06caSMauro Carvalho Chehab 690c0d06caSMauro Carvalho Chehab static ssize_t show_name(struct device *class_dev, 700c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 710c0d06caSMauro Carvalho Chehab char *buf) 720c0d06caSMauro Carvalho Chehab { 730c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 740c0d06caSMauro Carvalho Chehab const char *name; 750c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name); 760c0d06caSMauro Carvalho Chehab name = pvr2_ctrl_get_desc(cip->cptr); 770c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s", 780c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, name); 790c0d06caSMauro Carvalho Chehab if (!name) return -EINVAL; 800c0d06caSMauro Carvalho Chehab return scnprintf(buf, PAGE_SIZE, "%s\n", name); 810c0d06caSMauro Carvalho Chehab } 820c0d06caSMauro Carvalho Chehab 830c0d06caSMauro Carvalho Chehab static ssize_t show_type(struct device *class_dev, 840c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 850c0d06caSMauro Carvalho Chehab char *buf) 860c0d06caSMauro Carvalho Chehab { 870c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 880c0d06caSMauro Carvalho Chehab const char *name; 890c0d06caSMauro Carvalho Chehab enum pvr2_ctl_type tp; 900c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type); 910c0d06caSMauro Carvalho Chehab tp = pvr2_ctrl_get_type(cip->cptr); 920c0d06caSMauro Carvalho Chehab switch (tp) { 930c0d06caSMauro Carvalho Chehab case pvr2_ctl_int: name = "integer"; break; 940c0d06caSMauro Carvalho Chehab case pvr2_ctl_enum: name = "enum"; break; 950c0d06caSMauro Carvalho Chehab case pvr2_ctl_bitmask: name = "bitmask"; break; 960c0d06caSMauro Carvalho Chehab case pvr2_ctl_bool: name = "boolean"; break; 970c0d06caSMauro Carvalho Chehab default: name = "?"; break; 980c0d06caSMauro Carvalho Chehab } 990c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", 1000c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, name); 1010c0d06caSMauro Carvalho Chehab return scnprintf(buf, PAGE_SIZE, "%s\n", name); 1020c0d06caSMauro Carvalho Chehab } 1030c0d06caSMauro Carvalho Chehab 1040c0d06caSMauro Carvalho Chehab static ssize_t show_min(struct device *class_dev, 1050c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1060c0d06caSMauro Carvalho Chehab char *buf) 1070c0d06caSMauro Carvalho Chehab { 1080c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1090c0d06caSMauro Carvalho Chehab long val; 1100c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min); 1110c0d06caSMauro Carvalho Chehab val = pvr2_ctrl_get_min(cip->cptr); 1120c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld", 1130c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, val); 1140c0d06caSMauro Carvalho Chehab return scnprintf(buf, PAGE_SIZE, "%ld\n", val); 1150c0d06caSMauro Carvalho Chehab } 1160c0d06caSMauro Carvalho Chehab 1170c0d06caSMauro Carvalho Chehab static ssize_t show_max(struct device *class_dev, 1180c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1190c0d06caSMauro Carvalho Chehab char *buf) 1200c0d06caSMauro Carvalho Chehab { 1210c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1220c0d06caSMauro Carvalho Chehab long val; 1230c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max); 1240c0d06caSMauro Carvalho Chehab val = pvr2_ctrl_get_max(cip->cptr); 1250c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld", 1260c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, val); 1270c0d06caSMauro Carvalho Chehab return scnprintf(buf, PAGE_SIZE, "%ld\n", val); 1280c0d06caSMauro Carvalho Chehab } 1290c0d06caSMauro Carvalho Chehab 1300c0d06caSMauro Carvalho Chehab static ssize_t show_def(struct device *class_dev, 1310c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1320c0d06caSMauro Carvalho Chehab char *buf) 1330c0d06caSMauro Carvalho Chehab { 1340c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1350c0d06caSMauro Carvalho Chehab int val; 1360c0d06caSMauro Carvalho Chehab int ret; 1370c0d06caSMauro Carvalho Chehab unsigned int cnt = 0; 1380c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def); 1390c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_get_def(cip->cptr, &val); 1400c0d06caSMauro Carvalho Chehab if (ret < 0) return ret; 1410c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, 1420c0d06caSMauro Carvalho Chehab buf, PAGE_SIZE - 1, &cnt); 1430c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %.*s (%d)", 1440c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, cnt, buf, val); 1450c0d06caSMauro Carvalho Chehab buf[cnt] = '\n'; 1460c0d06caSMauro Carvalho Chehab return cnt + 1; 1470c0d06caSMauro Carvalho Chehab } 1480c0d06caSMauro Carvalho Chehab 1490c0d06caSMauro Carvalho Chehab static ssize_t show_val_norm(struct device *class_dev, 1500c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1510c0d06caSMauro Carvalho Chehab char *buf) 1520c0d06caSMauro Carvalho Chehab { 1530c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1540c0d06caSMauro Carvalho Chehab int val; 1550c0d06caSMauro Carvalho Chehab int ret; 1560c0d06caSMauro Carvalho Chehab unsigned int cnt = 0; 1570c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); 1580c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_get_value(cip->cptr, &val); 1590c0d06caSMauro Carvalho Chehab if (ret < 0) return ret; 1600c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, 1610c0d06caSMauro Carvalho Chehab buf, PAGE_SIZE - 1, &cnt); 1620c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", 1630c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, cnt, buf, val); 1640c0d06caSMauro Carvalho Chehab buf[cnt] = '\n'; 1650c0d06caSMauro Carvalho Chehab return cnt+1; 1660c0d06caSMauro Carvalho Chehab } 1670c0d06caSMauro Carvalho Chehab 1680c0d06caSMauro Carvalho Chehab static ssize_t show_val_custom(struct device *class_dev, 1690c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1700c0d06caSMauro Carvalho Chehab char *buf) 1710c0d06caSMauro Carvalho Chehab { 1720c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1730c0d06caSMauro Carvalho Chehab int val; 1740c0d06caSMauro Carvalho Chehab int ret; 1750c0d06caSMauro Carvalho Chehab unsigned int cnt = 0; 1760c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); 1770c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_get_value(cip->cptr, &val); 1780c0d06caSMauro Carvalho Chehab if (ret < 0) return ret; 1790c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val, 1800c0d06caSMauro Carvalho Chehab buf, PAGE_SIZE - 1, &cnt); 1810c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", 1820c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, cnt, buf, val); 1830c0d06caSMauro Carvalho Chehab buf[cnt] = '\n'; 1840c0d06caSMauro Carvalho Chehab return cnt+1; 1850c0d06caSMauro Carvalho Chehab } 1860c0d06caSMauro Carvalho Chehab 1870c0d06caSMauro Carvalho Chehab static ssize_t show_enum(struct device *class_dev, 1880c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 1890c0d06caSMauro Carvalho Chehab char *buf) 1900c0d06caSMauro Carvalho Chehab { 1910c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 1920c0d06caSMauro Carvalho Chehab long val; 1930c0d06caSMauro Carvalho Chehab unsigned int bcnt, ccnt, ecnt; 1940c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum); 1950c0d06caSMauro Carvalho Chehab ecnt = pvr2_ctrl_get_cnt(cip->cptr); 1960c0d06caSMauro Carvalho Chehab bcnt = 0; 1970c0d06caSMauro Carvalho Chehab for (val = 0; val < ecnt; val++) { 1980c0d06caSMauro Carvalho Chehab pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt, 1990c0d06caSMauro Carvalho Chehab PAGE_SIZE - bcnt, &ccnt); 2000c0d06caSMauro Carvalho Chehab if (!ccnt) continue; 2010c0d06caSMauro Carvalho Chehab bcnt += ccnt; 2020c0d06caSMauro Carvalho Chehab if (bcnt >= PAGE_SIZE) break; 2030c0d06caSMauro Carvalho Chehab buf[bcnt] = '\n'; 2040c0d06caSMauro Carvalho Chehab bcnt++; 2050c0d06caSMauro Carvalho Chehab } 2060c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)", 2070c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id); 2080c0d06caSMauro Carvalho Chehab return bcnt; 2090c0d06caSMauro Carvalho Chehab } 2100c0d06caSMauro Carvalho Chehab 2110c0d06caSMauro Carvalho Chehab static ssize_t show_bits(struct device *class_dev, 2120c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 2130c0d06caSMauro Carvalho Chehab char *buf) 2140c0d06caSMauro Carvalho Chehab { 2150c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 2160c0d06caSMauro Carvalho Chehab int valid_bits, msk; 2170c0d06caSMauro Carvalho Chehab unsigned int bcnt, ccnt; 2180c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits); 2190c0d06caSMauro Carvalho Chehab valid_bits = pvr2_ctrl_get_mask(cip->cptr); 2200c0d06caSMauro Carvalho Chehab bcnt = 0; 2210c0d06caSMauro Carvalho Chehab for (msk = 1; valid_bits; msk <<= 1) { 2220c0d06caSMauro Carvalho Chehab if (!(msk & valid_bits)) continue; 2230c0d06caSMauro Carvalho Chehab valid_bits &= ~msk; 2240c0d06caSMauro Carvalho Chehab pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt, 2250c0d06caSMauro Carvalho Chehab PAGE_SIZE - bcnt, &ccnt); 2260c0d06caSMauro Carvalho Chehab bcnt += ccnt; 2270c0d06caSMauro Carvalho Chehab if (bcnt >= PAGE_SIZE) break; 2280c0d06caSMauro Carvalho Chehab buf[bcnt] = '\n'; 2290c0d06caSMauro Carvalho Chehab bcnt++; 2300c0d06caSMauro Carvalho Chehab } 2310c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)", 2320c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id); 2330c0d06caSMauro Carvalho Chehab return bcnt; 2340c0d06caSMauro Carvalho Chehab } 2350c0d06caSMauro Carvalho Chehab 2360c0d06caSMauro Carvalho Chehab static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl, 2370c0d06caSMauro Carvalho Chehab const char *buf,unsigned int count) 2380c0d06caSMauro Carvalho Chehab { 2390c0d06caSMauro Carvalho Chehab int ret; 2400c0d06caSMauro Carvalho Chehab int mask,val; 2410c0d06caSMauro Carvalho Chehab if (customfl) { 2420c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count, 2430c0d06caSMauro Carvalho Chehab &mask, &val); 2440c0d06caSMauro Carvalho Chehab } else { 2450c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count, 2460c0d06caSMauro Carvalho Chehab &mask, &val); 2470c0d06caSMauro Carvalho Chehab } 2480c0d06caSMauro Carvalho Chehab if (ret < 0) return ret; 2490c0d06caSMauro Carvalho Chehab ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val); 2500c0d06caSMauro Carvalho Chehab pvr2_hdw_commit_ctl(cip->chptr->channel.hdw); 2510c0d06caSMauro Carvalho Chehab return ret; 2520c0d06caSMauro Carvalho Chehab } 2530c0d06caSMauro Carvalho Chehab 2540c0d06caSMauro Carvalho Chehab static ssize_t store_val_norm(struct device *class_dev, 2550c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 2560c0d06caSMauro Carvalho Chehab const char *buf, size_t count) 2570c0d06caSMauro Carvalho Chehab { 2580c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 2590c0d06caSMauro Carvalho Chehab int ret; 2600c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); 2610c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"", 2620c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, (int)count, buf); 2630c0d06caSMauro Carvalho Chehab ret = store_val_any(cip, 0, buf, count); 2640c0d06caSMauro Carvalho Chehab if (!ret) ret = count; 2650c0d06caSMauro Carvalho Chehab return ret; 2660c0d06caSMauro Carvalho Chehab } 2670c0d06caSMauro Carvalho Chehab 2680c0d06caSMauro Carvalho Chehab static ssize_t store_val_custom(struct device *class_dev, 2690c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 2700c0d06caSMauro Carvalho Chehab const char *buf, size_t count) 2710c0d06caSMauro Carvalho Chehab { 2720c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 2730c0d06caSMauro Carvalho Chehab int ret; 2740c0d06caSMauro Carvalho Chehab cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); 2750c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"", 2760c0d06caSMauro Carvalho Chehab cip->chptr, cip->ctl_id, (int)count, buf); 2770c0d06caSMauro Carvalho Chehab ret = store_val_any(cip, 1, buf, count); 2780c0d06caSMauro Carvalho Chehab if (!ret) ret = count; 2790c0d06caSMauro Carvalho Chehab return ret; 2800c0d06caSMauro Carvalho Chehab } 2810c0d06caSMauro Carvalho Chehab 2820c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) 2830c0d06caSMauro Carvalho Chehab { 2840c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip; 2850c0d06caSMauro Carvalho Chehab struct pvr2_ctrl *cptr; 2860c0d06caSMauro Carvalho Chehab unsigned int cnt,acnt; 2870c0d06caSMauro Carvalho Chehab int ret; 2880c0d06caSMauro Carvalho Chehab 2890c0d06caSMauro Carvalho Chehab cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); 2900c0d06caSMauro Carvalho Chehab if (!cptr) return; 2910c0d06caSMauro Carvalho Chehab 2920c0d06caSMauro Carvalho Chehab cip = kzalloc(sizeof(*cip),GFP_KERNEL); 2930c0d06caSMauro Carvalho Chehab if (!cip) return; 2940c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); 2950c0d06caSMauro Carvalho Chehab 2960c0d06caSMauro Carvalho Chehab cip->cptr = cptr; 2970c0d06caSMauro Carvalho Chehab cip->ctl_id = ctl_id; 2980c0d06caSMauro Carvalho Chehab 2990c0d06caSMauro Carvalho Chehab cip->chptr = sfp; 3000c0d06caSMauro Carvalho Chehab cip->item_next = NULL; 3010c0d06caSMauro Carvalho Chehab if (sfp->item_last) { 3020c0d06caSMauro Carvalho Chehab sfp->item_last->item_next = cip; 3030c0d06caSMauro Carvalho Chehab } else { 3040c0d06caSMauro Carvalho Chehab sfp->item_first = cip; 3050c0d06caSMauro Carvalho Chehab } 3060c0d06caSMauro Carvalho Chehab sfp->item_last = cip; 3070c0d06caSMauro Carvalho Chehab 3080c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_name.attr); 3090c0d06caSMauro Carvalho Chehab cip->attr_name.attr.name = "name"; 3100c0d06caSMauro Carvalho Chehab cip->attr_name.attr.mode = S_IRUGO; 3110c0d06caSMauro Carvalho Chehab cip->attr_name.show = show_name; 3120c0d06caSMauro Carvalho Chehab 3130c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_type.attr); 3140c0d06caSMauro Carvalho Chehab cip->attr_type.attr.name = "type"; 3150c0d06caSMauro Carvalho Chehab cip->attr_type.attr.mode = S_IRUGO; 3160c0d06caSMauro Carvalho Chehab cip->attr_type.show = show_type; 3170c0d06caSMauro Carvalho Chehab 3180c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_min.attr); 3190c0d06caSMauro Carvalho Chehab cip->attr_min.attr.name = "min_val"; 3200c0d06caSMauro Carvalho Chehab cip->attr_min.attr.mode = S_IRUGO; 3210c0d06caSMauro Carvalho Chehab cip->attr_min.show = show_min; 3220c0d06caSMauro Carvalho Chehab 3230c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_max.attr); 3240c0d06caSMauro Carvalho Chehab cip->attr_max.attr.name = "max_val"; 3250c0d06caSMauro Carvalho Chehab cip->attr_max.attr.mode = S_IRUGO; 3260c0d06caSMauro Carvalho Chehab cip->attr_max.show = show_max; 3270c0d06caSMauro Carvalho Chehab 3280c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_def.attr); 3290c0d06caSMauro Carvalho Chehab cip->attr_def.attr.name = "def_val"; 3300c0d06caSMauro Carvalho Chehab cip->attr_def.attr.mode = S_IRUGO; 3310c0d06caSMauro Carvalho Chehab cip->attr_def.show = show_def; 3320c0d06caSMauro Carvalho Chehab 3330c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_val.attr); 3340c0d06caSMauro Carvalho Chehab cip->attr_val.attr.name = "cur_val"; 3350c0d06caSMauro Carvalho Chehab cip->attr_val.attr.mode = S_IRUGO; 3360c0d06caSMauro Carvalho Chehab 3370c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_custom.attr); 3380c0d06caSMauro Carvalho Chehab cip->attr_custom.attr.name = "custom_val"; 3390c0d06caSMauro Carvalho Chehab cip->attr_custom.attr.mode = S_IRUGO; 3400c0d06caSMauro Carvalho Chehab 3410c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_enum.attr); 3420c0d06caSMauro Carvalho Chehab cip->attr_enum.attr.name = "enum_val"; 3430c0d06caSMauro Carvalho Chehab cip->attr_enum.attr.mode = S_IRUGO; 3440c0d06caSMauro Carvalho Chehab cip->attr_enum.show = show_enum; 3450c0d06caSMauro Carvalho Chehab 3460c0d06caSMauro Carvalho Chehab sysfs_attr_init(&cip->attr_bits.attr); 3470c0d06caSMauro Carvalho Chehab cip->attr_bits.attr.name = "bit_val"; 3480c0d06caSMauro Carvalho Chehab cip->attr_bits.attr.mode = S_IRUGO; 3490c0d06caSMauro Carvalho Chehab cip->attr_bits.show = show_bits; 3500c0d06caSMauro Carvalho Chehab 3510c0d06caSMauro Carvalho Chehab if (pvr2_ctrl_is_writable(cptr)) { 3520c0d06caSMauro Carvalho Chehab cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; 3530c0d06caSMauro Carvalho Chehab cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP; 3540c0d06caSMauro Carvalho Chehab } 3550c0d06caSMauro Carvalho Chehab 3560c0d06caSMauro Carvalho Chehab acnt = 0; 3570c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_name.attr; 3580c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_type.attr; 3590c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_val.attr; 3600c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_def.attr; 3610c0d06caSMauro Carvalho Chehab cip->attr_val.show = show_val_norm; 3620c0d06caSMauro Carvalho Chehab cip->attr_val.store = store_val_norm; 3630c0d06caSMauro Carvalho Chehab if (pvr2_ctrl_has_custom_symbols(cptr)) { 3640c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_custom.attr; 3650c0d06caSMauro Carvalho Chehab cip->attr_custom.show = show_val_custom; 3660c0d06caSMauro Carvalho Chehab cip->attr_custom.store = store_val_custom; 3670c0d06caSMauro Carvalho Chehab } 3680c0d06caSMauro Carvalho Chehab switch (pvr2_ctrl_get_type(cptr)) { 3690c0d06caSMauro Carvalho Chehab case pvr2_ctl_enum: 3700c0d06caSMauro Carvalho Chehab // Control is an enumeration 3710c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_enum.attr; 3720c0d06caSMauro Carvalho Chehab break; 3730c0d06caSMauro Carvalho Chehab case pvr2_ctl_int: 3740c0d06caSMauro Carvalho Chehab // Control is an integer 3750c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_min.attr; 3760c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_max.attr; 3770c0d06caSMauro Carvalho Chehab break; 3780c0d06caSMauro Carvalho Chehab case pvr2_ctl_bitmask: 3790c0d06caSMauro Carvalho Chehab // Control is an bitmask 3800c0d06caSMauro Carvalho Chehab cip->attr_gen[acnt++] = &cip->attr_bits.attr; 3810c0d06caSMauro Carvalho Chehab break; 3820c0d06caSMauro Carvalho Chehab default: break; 3830c0d06caSMauro Carvalho Chehab } 3840c0d06caSMauro Carvalho Chehab 3850c0d06caSMauro Carvalho Chehab cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s", 3860c0d06caSMauro Carvalho Chehab pvr2_ctrl_get_name(cptr)); 3870c0d06caSMauro Carvalho Chehab cip->name[cnt] = 0; 3880c0d06caSMauro Carvalho Chehab cip->grp.name = cip->name; 3890c0d06caSMauro Carvalho Chehab cip->grp.attrs = cip->attr_gen; 3900c0d06caSMauro Carvalho Chehab 3910c0d06caSMauro Carvalho Chehab ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); 3920c0d06caSMauro Carvalho Chehab if (ret) { 3930c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 3940c0d06caSMauro Carvalho Chehab "sysfs_create_group error: %d", 3950c0d06caSMauro Carvalho Chehab ret); 3960c0d06caSMauro Carvalho Chehab return; 3970c0d06caSMauro Carvalho Chehab } 3980c0d06caSMauro Carvalho Chehab cip->created_ok = !0; 3990c0d06caSMauro Carvalho Chehab } 4000c0d06caSMauro Carvalho Chehab 4010c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 4020c0d06caSMauro Carvalho Chehab static ssize_t debuginfo_show(struct device *, struct device_attribute *, 4030c0d06caSMauro Carvalho Chehab char *); 4040c0d06caSMauro Carvalho Chehab static ssize_t debugcmd_show(struct device *, struct device_attribute *, 4050c0d06caSMauro Carvalho Chehab char *); 4060c0d06caSMauro Carvalho Chehab static ssize_t debugcmd_store(struct device *, struct device_attribute *, 4070c0d06caSMauro Carvalho Chehab const char *, size_t count); 4080c0d06caSMauro Carvalho Chehab 4090c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) 4100c0d06caSMauro Carvalho Chehab { 4110c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_debugifc *dip; 4120c0d06caSMauro Carvalho Chehab int ret; 4130c0d06caSMauro Carvalho Chehab 4140c0d06caSMauro Carvalho Chehab dip = kzalloc(sizeof(*dip),GFP_KERNEL); 4150c0d06caSMauro Carvalho Chehab if (!dip) return; 4160c0d06caSMauro Carvalho Chehab sysfs_attr_init(&dip->attr_debugcmd.attr); 4170c0d06caSMauro Carvalho Chehab dip->attr_debugcmd.attr.name = "debugcmd"; 4180c0d06caSMauro Carvalho Chehab dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; 4190c0d06caSMauro Carvalho Chehab dip->attr_debugcmd.show = debugcmd_show; 4200c0d06caSMauro Carvalho Chehab dip->attr_debugcmd.store = debugcmd_store; 4210c0d06caSMauro Carvalho Chehab sysfs_attr_init(&dip->attr_debuginfo.attr); 4220c0d06caSMauro Carvalho Chehab dip->attr_debuginfo.attr.name = "debuginfo"; 4230c0d06caSMauro Carvalho Chehab dip->attr_debuginfo.attr.mode = S_IRUGO; 4240c0d06caSMauro Carvalho Chehab dip->attr_debuginfo.show = debuginfo_show; 4250c0d06caSMauro Carvalho Chehab sfp->debugifc = dip; 4260c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); 4270c0d06caSMauro Carvalho Chehab if (ret < 0) { 4280c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 4290c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 4300c0d06caSMauro Carvalho Chehab ret); 4310c0d06caSMauro Carvalho Chehab } else { 4320c0d06caSMauro Carvalho Chehab dip->debugcmd_created_ok = !0; 4330c0d06caSMauro Carvalho Chehab } 4340c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); 4350c0d06caSMauro Carvalho Chehab if (ret < 0) { 4360c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 4370c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 4380c0d06caSMauro Carvalho Chehab ret); 4390c0d06caSMauro Carvalho Chehab } else { 4400c0d06caSMauro Carvalho Chehab dip->debuginfo_created_ok = !0; 4410c0d06caSMauro Carvalho Chehab } 4420c0d06caSMauro Carvalho Chehab } 4430c0d06caSMauro Carvalho Chehab 4440c0d06caSMauro Carvalho Chehab 4450c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) 4460c0d06caSMauro Carvalho Chehab { 4470c0d06caSMauro Carvalho Chehab if (!sfp->debugifc) return; 4480c0d06caSMauro Carvalho Chehab if (sfp->debugifc->debuginfo_created_ok) { 4490c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 4500c0d06caSMauro Carvalho Chehab &sfp->debugifc->attr_debuginfo); 4510c0d06caSMauro Carvalho Chehab } 4520c0d06caSMauro Carvalho Chehab if (sfp->debugifc->debugcmd_created_ok) { 4530c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 4540c0d06caSMauro Carvalho Chehab &sfp->debugifc->attr_debugcmd); 4550c0d06caSMauro Carvalho Chehab } 4560c0d06caSMauro Carvalho Chehab kfree(sfp->debugifc); 4570c0d06caSMauro Carvalho Chehab sfp->debugifc = NULL; 4580c0d06caSMauro Carvalho Chehab } 4590c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 4600c0d06caSMauro Carvalho Chehab 4610c0d06caSMauro Carvalho Chehab 4620c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp) 4630c0d06caSMauro Carvalho Chehab { 4640c0d06caSMauro Carvalho Chehab unsigned int idx,cnt; 4650c0d06caSMauro Carvalho Chehab cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw); 4660c0d06caSMauro Carvalho Chehab for (idx = 0; idx < cnt; idx++) { 4670c0d06caSMauro Carvalho Chehab pvr2_sysfs_add_control(sfp,idx); 4680c0d06caSMauro Carvalho Chehab } 4690c0d06caSMauro Carvalho Chehab } 4700c0d06caSMauro Carvalho Chehab 4710c0d06caSMauro Carvalho Chehab 4720c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) 4730c0d06caSMauro Carvalho Chehab { 4740c0d06caSMauro Carvalho Chehab struct pvr2_sysfs_ctl_item *cip1,*cip2; 4750c0d06caSMauro Carvalho Chehab for (cip1 = sfp->item_first; cip1; cip1 = cip2) { 4760c0d06caSMauro Carvalho Chehab cip2 = cip1->item_next; 4770c0d06caSMauro Carvalho Chehab if (cip1->created_ok) { 4780c0d06caSMauro Carvalho Chehab sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); 4790c0d06caSMauro Carvalho Chehab } 4800c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); 4810c0d06caSMauro Carvalho Chehab kfree(cip1); 4820c0d06caSMauro Carvalho Chehab } 4830c0d06caSMauro Carvalho Chehab } 4840c0d06caSMauro Carvalho Chehab 4850c0d06caSMauro Carvalho Chehab 4860c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_release(struct device *class_dev) 4870c0d06caSMauro Carvalho Chehab { 4880c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); 4890c0d06caSMauro Carvalho Chehab kfree(class_dev); 4900c0d06caSMauro Carvalho Chehab } 4910c0d06caSMauro Carvalho Chehab 4920c0d06caSMauro Carvalho Chehab 493*6332a6ceSGreg Kroah-Hartman static struct class pvr2_class = { 494*6332a6ceSGreg Kroah-Hartman .name = "pvrusb2", 495*6332a6ceSGreg Kroah-Hartman .dev_release = pvr2_sysfs_release, 496*6332a6ceSGreg Kroah-Hartman }; 497*6332a6ceSGreg Kroah-Hartman 498*6332a6ceSGreg Kroah-Hartman 4990c0d06caSMauro Carvalho Chehab static void class_dev_destroy(struct pvr2_sysfs *sfp) 5000c0d06caSMauro Carvalho Chehab { 5010c0d06caSMauro Carvalho Chehab struct device *dev; 5020c0d06caSMauro Carvalho Chehab if (!sfp->class_dev) return; 5030c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 5040c0d06caSMauro Carvalho Chehab pvr2_sysfs_tear_down_debugifc(sfp); 5050c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 5060c0d06caSMauro Carvalho Chehab pvr2_sysfs_tear_down_controls(sfp); 5070c0d06caSMauro Carvalho Chehab if (sfp->hdw_desc_created_ok) { 5080c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5090c0d06caSMauro Carvalho Chehab &sfp->attr_hdw_desc); 5100c0d06caSMauro Carvalho Chehab } 5110c0d06caSMauro Carvalho Chehab if (sfp->hdw_name_created_ok) { 5120c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5130c0d06caSMauro Carvalho Chehab &sfp->attr_hdw_name); 5140c0d06caSMauro Carvalho Chehab } 5150c0d06caSMauro Carvalho Chehab if (sfp->bus_info_created_ok) { 5160c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5170c0d06caSMauro Carvalho Chehab &sfp->attr_bus_info); 5180c0d06caSMauro Carvalho Chehab } 5190c0d06caSMauro Carvalho Chehab if (sfp->v4l_minor_number_created_ok) { 5200c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5210c0d06caSMauro Carvalho Chehab &sfp->attr_v4l_minor_number); 5220c0d06caSMauro Carvalho Chehab } 5230c0d06caSMauro Carvalho Chehab if (sfp->v4l_radio_minor_number_created_ok) { 5240c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5250c0d06caSMauro Carvalho Chehab &sfp->attr_v4l_radio_minor_number); 5260c0d06caSMauro Carvalho Chehab } 5270c0d06caSMauro Carvalho Chehab if (sfp->unit_number_created_ok) { 5280c0d06caSMauro Carvalho Chehab device_remove_file(sfp->class_dev, 5290c0d06caSMauro Carvalho Chehab &sfp->attr_unit_number); 5300c0d06caSMauro Carvalho Chehab } 5310c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); 5320c0d06caSMauro Carvalho Chehab dev_set_drvdata(sfp->class_dev, NULL); 5330c0d06caSMauro Carvalho Chehab dev = sfp->class_dev->parent; 5340c0d06caSMauro Carvalho Chehab sfp->class_dev->parent = NULL; 5350c0d06caSMauro Carvalho Chehab put_device(dev); 5360c0d06caSMauro Carvalho Chehab device_unregister(sfp->class_dev); 5370c0d06caSMauro Carvalho Chehab sfp->class_dev = NULL; 5380c0d06caSMauro Carvalho Chehab } 5390c0d06caSMauro Carvalho Chehab 5400c0d06caSMauro Carvalho Chehab 5410c0d06caSMauro Carvalho Chehab static ssize_t v4l_minor_number_show(struct device *class_dev, 5420c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 5430c0d06caSMauro Carvalho Chehab { 5440c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 5450c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 5460c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 5470c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%d\n", 5480c0d06caSMauro Carvalho Chehab pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, 5490c0d06caSMauro Carvalho Chehab pvr2_v4l_type_video)); 5500c0d06caSMauro Carvalho Chehab } 5510c0d06caSMauro Carvalho Chehab 5520c0d06caSMauro Carvalho Chehab 5530c0d06caSMauro Carvalho Chehab static ssize_t bus_info_show(struct device *class_dev, 5540c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 5550c0d06caSMauro Carvalho Chehab { 5560c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 5570c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 5580c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 5590c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%s\n", 5600c0d06caSMauro Carvalho Chehab pvr2_hdw_get_bus_info(sfp->channel.hdw)); 5610c0d06caSMauro Carvalho Chehab } 5620c0d06caSMauro Carvalho Chehab 5630c0d06caSMauro Carvalho Chehab 5640c0d06caSMauro Carvalho Chehab static ssize_t hdw_name_show(struct device *class_dev, 5650c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 5660c0d06caSMauro Carvalho Chehab { 5670c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 5680c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 5690c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 5700c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%s\n", 5710c0d06caSMauro Carvalho Chehab pvr2_hdw_get_type(sfp->channel.hdw)); 5720c0d06caSMauro Carvalho Chehab } 5730c0d06caSMauro Carvalho Chehab 5740c0d06caSMauro Carvalho Chehab 5750c0d06caSMauro Carvalho Chehab static ssize_t hdw_desc_show(struct device *class_dev, 5760c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 5770c0d06caSMauro Carvalho Chehab { 5780c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 5790c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 5800c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 5810c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%s\n", 5820c0d06caSMauro Carvalho Chehab pvr2_hdw_get_desc(sfp->channel.hdw)); 5830c0d06caSMauro Carvalho Chehab } 5840c0d06caSMauro Carvalho Chehab 5850c0d06caSMauro Carvalho Chehab 5860c0d06caSMauro Carvalho Chehab static ssize_t v4l_radio_minor_number_show(struct device *class_dev, 5870c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 5880c0d06caSMauro Carvalho Chehab char *buf) 5890c0d06caSMauro Carvalho Chehab { 5900c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 5910c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 5920c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 5930c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%d\n", 5940c0d06caSMauro Carvalho Chehab pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, 5950c0d06caSMauro Carvalho Chehab pvr2_v4l_type_radio)); 5960c0d06caSMauro Carvalho Chehab } 5970c0d06caSMauro Carvalho Chehab 5980c0d06caSMauro Carvalho Chehab 5990c0d06caSMauro Carvalho Chehab static ssize_t unit_number_show(struct device *class_dev, 6000c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 6010c0d06caSMauro Carvalho Chehab { 6020c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 6030c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 6040c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 6050c0d06caSMauro Carvalho Chehab return scnprintf(buf,PAGE_SIZE,"%d\n", 6060c0d06caSMauro Carvalho Chehab pvr2_hdw_get_unit_number(sfp->channel.hdw)); 6070c0d06caSMauro Carvalho Chehab } 6080c0d06caSMauro Carvalho Chehab 6090c0d06caSMauro Carvalho Chehab 610*6332a6ceSGreg Kroah-Hartman static void class_dev_create(struct pvr2_sysfs *sfp) 6110c0d06caSMauro Carvalho Chehab { 6120c0d06caSMauro Carvalho Chehab struct usb_device *usb_dev; 6130c0d06caSMauro Carvalho Chehab struct device *class_dev; 6140c0d06caSMauro Carvalho Chehab int ret; 6150c0d06caSMauro Carvalho Chehab 6160c0d06caSMauro Carvalho Chehab usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); 6170c0d06caSMauro Carvalho Chehab if (!usb_dev) return; 6180c0d06caSMauro Carvalho Chehab class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL); 6190c0d06caSMauro Carvalho Chehab if (!class_dev) return; 6200c0d06caSMauro Carvalho Chehab 6210c0d06caSMauro Carvalho Chehab pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); 6220c0d06caSMauro Carvalho Chehab 623*6332a6ceSGreg Kroah-Hartman class_dev->class = &pvr2_class; 6240c0d06caSMauro Carvalho Chehab 6250c0d06caSMauro Carvalho Chehab dev_set_name(class_dev, "%s", 6260c0d06caSMauro Carvalho Chehab pvr2_hdw_get_device_identifier(sfp->channel.hdw)); 6270c0d06caSMauro Carvalho Chehab 6280c0d06caSMauro Carvalho Chehab class_dev->parent = get_device(&usb_dev->dev); 6290c0d06caSMauro Carvalho Chehab 6300c0d06caSMauro Carvalho Chehab sfp->class_dev = class_dev; 6310c0d06caSMauro Carvalho Chehab dev_set_drvdata(class_dev, sfp); 6320c0d06caSMauro Carvalho Chehab ret = device_register(class_dev); 6330c0d06caSMauro Carvalho Chehab if (ret) { 6340c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6350c0d06caSMauro Carvalho Chehab "device_register failed"); 6360c0d06caSMauro Carvalho Chehab put_device(class_dev); 6370c0d06caSMauro Carvalho Chehab return; 6380c0d06caSMauro Carvalho Chehab } 6390c0d06caSMauro Carvalho Chehab 6400c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); 6410c0d06caSMauro Carvalho Chehab sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; 6420c0d06caSMauro Carvalho Chehab sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; 6430c0d06caSMauro Carvalho Chehab sfp->attr_v4l_minor_number.show = v4l_minor_number_show; 6440c0d06caSMauro Carvalho Chehab sfp->attr_v4l_minor_number.store = NULL; 6450c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev, 6460c0d06caSMauro Carvalho Chehab &sfp->attr_v4l_minor_number); 6470c0d06caSMauro Carvalho Chehab if (ret < 0) { 6480c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6490c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 6500c0d06caSMauro Carvalho Chehab ret); 6510c0d06caSMauro Carvalho Chehab } else { 6520c0d06caSMauro Carvalho Chehab sfp->v4l_minor_number_created_ok = !0; 6530c0d06caSMauro Carvalho Chehab } 6540c0d06caSMauro Carvalho Chehab 6550c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); 6560c0d06caSMauro Carvalho Chehab sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; 6570c0d06caSMauro Carvalho Chehab sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; 6580c0d06caSMauro Carvalho Chehab sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; 6590c0d06caSMauro Carvalho Chehab sfp->attr_v4l_radio_minor_number.store = NULL; 6600c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev, 6610c0d06caSMauro Carvalho Chehab &sfp->attr_v4l_radio_minor_number); 6620c0d06caSMauro Carvalho Chehab if (ret < 0) { 6630c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6640c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 6650c0d06caSMauro Carvalho Chehab ret); 6660c0d06caSMauro Carvalho Chehab } else { 6670c0d06caSMauro Carvalho Chehab sfp->v4l_radio_minor_number_created_ok = !0; 6680c0d06caSMauro Carvalho Chehab } 6690c0d06caSMauro Carvalho Chehab 6700c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_unit_number.attr); 6710c0d06caSMauro Carvalho Chehab sfp->attr_unit_number.attr.name = "unit_number"; 6720c0d06caSMauro Carvalho Chehab sfp->attr_unit_number.attr.mode = S_IRUGO; 6730c0d06caSMauro Carvalho Chehab sfp->attr_unit_number.show = unit_number_show; 6740c0d06caSMauro Carvalho Chehab sfp->attr_unit_number.store = NULL; 6750c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); 6760c0d06caSMauro Carvalho Chehab if (ret < 0) { 6770c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6780c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 6790c0d06caSMauro Carvalho Chehab ret); 6800c0d06caSMauro Carvalho Chehab } else { 6810c0d06caSMauro Carvalho Chehab sfp->unit_number_created_ok = !0; 6820c0d06caSMauro Carvalho Chehab } 6830c0d06caSMauro Carvalho Chehab 6840c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_bus_info.attr); 6850c0d06caSMauro Carvalho Chehab sfp->attr_bus_info.attr.name = "bus_info_str"; 6860c0d06caSMauro Carvalho Chehab sfp->attr_bus_info.attr.mode = S_IRUGO; 6870c0d06caSMauro Carvalho Chehab sfp->attr_bus_info.show = bus_info_show; 6880c0d06caSMauro Carvalho Chehab sfp->attr_bus_info.store = NULL; 6890c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev, 6900c0d06caSMauro Carvalho Chehab &sfp->attr_bus_info); 6910c0d06caSMauro Carvalho Chehab if (ret < 0) { 6920c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6930c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 6940c0d06caSMauro Carvalho Chehab ret); 6950c0d06caSMauro Carvalho Chehab } else { 6960c0d06caSMauro Carvalho Chehab sfp->bus_info_created_ok = !0; 6970c0d06caSMauro Carvalho Chehab } 6980c0d06caSMauro Carvalho Chehab 6990c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_hdw_name.attr); 7000c0d06caSMauro Carvalho Chehab sfp->attr_hdw_name.attr.name = "device_hardware_type"; 7010c0d06caSMauro Carvalho Chehab sfp->attr_hdw_name.attr.mode = S_IRUGO; 7020c0d06caSMauro Carvalho Chehab sfp->attr_hdw_name.show = hdw_name_show; 7030c0d06caSMauro Carvalho Chehab sfp->attr_hdw_name.store = NULL; 7040c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev, 7050c0d06caSMauro Carvalho Chehab &sfp->attr_hdw_name); 7060c0d06caSMauro Carvalho Chehab if (ret < 0) { 7070c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 7080c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 7090c0d06caSMauro Carvalho Chehab ret); 7100c0d06caSMauro Carvalho Chehab } else { 7110c0d06caSMauro Carvalho Chehab sfp->hdw_name_created_ok = !0; 7120c0d06caSMauro Carvalho Chehab } 7130c0d06caSMauro Carvalho Chehab 7140c0d06caSMauro Carvalho Chehab sysfs_attr_init(&sfp->attr_hdw_desc.attr); 7150c0d06caSMauro Carvalho Chehab sfp->attr_hdw_desc.attr.name = "device_hardware_description"; 7160c0d06caSMauro Carvalho Chehab sfp->attr_hdw_desc.attr.mode = S_IRUGO; 7170c0d06caSMauro Carvalho Chehab sfp->attr_hdw_desc.show = hdw_desc_show; 7180c0d06caSMauro Carvalho Chehab sfp->attr_hdw_desc.store = NULL; 7190c0d06caSMauro Carvalho Chehab ret = device_create_file(sfp->class_dev, 7200c0d06caSMauro Carvalho Chehab &sfp->attr_hdw_desc); 7210c0d06caSMauro Carvalho Chehab if (ret < 0) { 7220c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, 7230c0d06caSMauro Carvalho Chehab "device_create_file error: %d", 7240c0d06caSMauro Carvalho Chehab ret); 7250c0d06caSMauro Carvalho Chehab } else { 7260c0d06caSMauro Carvalho Chehab sfp->hdw_desc_created_ok = !0; 7270c0d06caSMauro Carvalho Chehab } 7280c0d06caSMauro Carvalho Chehab 7290c0d06caSMauro Carvalho Chehab pvr2_sysfs_add_controls(sfp); 7300c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 7310c0d06caSMauro Carvalho Chehab pvr2_sysfs_add_debugifc(sfp); 7320c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 7330c0d06caSMauro Carvalho Chehab } 7340c0d06caSMauro Carvalho Chehab 7350c0d06caSMauro Carvalho Chehab 7360c0d06caSMauro Carvalho Chehab static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) 7370c0d06caSMauro Carvalho Chehab { 7380c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 7390c0d06caSMauro Carvalho Chehab sfp = container_of(chp,struct pvr2_sysfs,channel); 7400c0d06caSMauro Carvalho Chehab if (!sfp->channel.mc_head->disconnect_flag) return; 7410c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp); 7420c0d06caSMauro Carvalho Chehab class_dev_destroy(sfp); 7430c0d06caSMauro Carvalho Chehab pvr2_channel_done(&sfp->channel); 7440c0d06caSMauro Carvalho Chehab kfree(sfp); 7450c0d06caSMauro Carvalho Chehab } 7460c0d06caSMauro Carvalho Chehab 7470c0d06caSMauro Carvalho Chehab 748*6332a6ceSGreg Kroah-Hartman void pvr2_sysfs_create(struct pvr2_context *mp) 7490c0d06caSMauro Carvalho Chehab { 7500c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 7510c0d06caSMauro Carvalho Chehab sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); 752*6332a6ceSGreg Kroah-Hartman if (!sfp) 753*6332a6ceSGreg Kroah-Hartman return; 7540c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); 7550c0d06caSMauro Carvalho Chehab pvr2_channel_init(&sfp->channel,mp); 7560c0d06caSMauro Carvalho Chehab sfp->channel.check_func = pvr2_sysfs_internal_check; 7570c0d06caSMauro Carvalho Chehab 758*6332a6ceSGreg Kroah-Hartman class_dev_create(sfp); 7590c0d06caSMauro Carvalho Chehab } 7600c0d06caSMauro Carvalho Chehab 7610c0d06caSMauro Carvalho Chehab 762*6332a6ceSGreg Kroah-Hartman void pvr2_sysfs_class_create(void) 7630c0d06caSMauro Carvalho Chehab { 764*6332a6ceSGreg Kroah-Hartman if (class_register(&pvr2_class)) 765*6332a6ceSGreg Kroah-Hartman pvr2_sysfs_trace("Registration failed for pvr2_sysfs_class"); 7660c0d06caSMauro Carvalho Chehab } 7670c0d06caSMauro Carvalho Chehab 7680c0d06caSMauro Carvalho Chehab 769*6332a6ceSGreg Kroah-Hartman void pvr2_sysfs_class_destroy(void) 7700c0d06caSMauro Carvalho Chehab { 771*6332a6ceSGreg Kroah-Hartman class_unregister(&pvr2_class); 7720c0d06caSMauro Carvalho Chehab } 7730c0d06caSMauro Carvalho Chehab 7740c0d06caSMauro Carvalho Chehab 7750c0d06caSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 7760c0d06caSMauro Carvalho Chehab static ssize_t debuginfo_show(struct device *class_dev, 7770c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 7780c0d06caSMauro Carvalho Chehab { 7790c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 7800c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 7810c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 7820c0d06caSMauro Carvalho Chehab pvr2_hdw_trigger_module_log(sfp->channel.hdw); 7830c0d06caSMauro Carvalho Chehab return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); 7840c0d06caSMauro Carvalho Chehab } 7850c0d06caSMauro Carvalho Chehab 7860c0d06caSMauro Carvalho Chehab 7870c0d06caSMauro Carvalho Chehab static ssize_t debugcmd_show(struct device *class_dev, 7880c0d06caSMauro Carvalho Chehab struct device_attribute *attr, char *buf) 7890c0d06caSMauro Carvalho Chehab { 7900c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 7910c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 7920c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 7930c0d06caSMauro Carvalho Chehab return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); 7940c0d06caSMauro Carvalho Chehab } 7950c0d06caSMauro Carvalho Chehab 7960c0d06caSMauro Carvalho Chehab 7970c0d06caSMauro Carvalho Chehab static ssize_t debugcmd_store(struct device *class_dev, 7980c0d06caSMauro Carvalho Chehab struct device_attribute *attr, 7990c0d06caSMauro Carvalho Chehab const char *buf, size_t count) 8000c0d06caSMauro Carvalho Chehab { 8010c0d06caSMauro Carvalho Chehab struct pvr2_sysfs *sfp; 8020c0d06caSMauro Carvalho Chehab int ret; 8030c0d06caSMauro Carvalho Chehab 8040c0d06caSMauro Carvalho Chehab sfp = dev_get_drvdata(class_dev); 8050c0d06caSMauro Carvalho Chehab if (!sfp) return -EINVAL; 8060c0d06caSMauro Carvalho Chehab 8070c0d06caSMauro Carvalho Chehab ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); 8080c0d06caSMauro Carvalho Chehab if (ret < 0) return ret; 8090c0d06caSMauro Carvalho Chehab return count; 8100c0d06caSMauro Carvalho Chehab } 8110c0d06caSMauro Carvalho Chehab #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 812