18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include "pvrusb2-sysfs.h" 108c2ecf20Sopenharmony_ci#include "pvrusb2-hdw.h" 118c2ecf20Sopenharmony_ci#include "pvrusb2-debug.h" 128c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 138c2ecf20Sopenharmony_ci#include "pvrusb2-debugifc.h" 148c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__) 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct pvr2_sysfs { 198c2ecf20Sopenharmony_ci struct pvr2_channel channel; 208c2ecf20Sopenharmony_ci struct device *class_dev; 218c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 228c2ecf20Sopenharmony_ci struct pvr2_sysfs_debugifc *debugifc; 238c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 248c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *item_first; 258c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *item_last; 268c2ecf20Sopenharmony_ci struct device_attribute attr_v4l_minor_number; 278c2ecf20Sopenharmony_ci struct device_attribute attr_v4l_radio_minor_number; 288c2ecf20Sopenharmony_ci struct device_attribute attr_unit_number; 298c2ecf20Sopenharmony_ci struct device_attribute attr_bus_info; 308c2ecf20Sopenharmony_ci struct device_attribute attr_hdw_name; 318c2ecf20Sopenharmony_ci struct device_attribute attr_hdw_desc; 328c2ecf20Sopenharmony_ci int v4l_minor_number_created_ok; 338c2ecf20Sopenharmony_ci int v4l_radio_minor_number_created_ok; 348c2ecf20Sopenharmony_ci int unit_number_created_ok; 358c2ecf20Sopenharmony_ci int bus_info_created_ok; 368c2ecf20Sopenharmony_ci int hdw_name_created_ok; 378c2ecf20Sopenharmony_ci int hdw_desc_created_ok; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 418c2ecf20Sopenharmony_cistruct pvr2_sysfs_debugifc { 428c2ecf20Sopenharmony_ci struct device_attribute attr_debugcmd; 438c2ecf20Sopenharmony_ci struct device_attribute attr_debuginfo; 448c2ecf20Sopenharmony_ci int debugcmd_created_ok; 458c2ecf20Sopenharmony_ci int debuginfo_created_ok; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct pvr2_sysfs_ctl_item { 508c2ecf20Sopenharmony_ci struct device_attribute attr_name; 518c2ecf20Sopenharmony_ci struct device_attribute attr_type; 528c2ecf20Sopenharmony_ci struct device_attribute attr_min; 538c2ecf20Sopenharmony_ci struct device_attribute attr_max; 548c2ecf20Sopenharmony_ci struct device_attribute attr_def; 558c2ecf20Sopenharmony_ci struct device_attribute attr_enum; 568c2ecf20Sopenharmony_ci struct device_attribute attr_bits; 578c2ecf20Sopenharmony_ci struct device_attribute attr_val; 588c2ecf20Sopenharmony_ci struct device_attribute attr_custom; 598c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 608c2ecf20Sopenharmony_ci int ctl_id; 618c2ecf20Sopenharmony_ci struct pvr2_sysfs *chptr; 628c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *item_next; 638c2ecf20Sopenharmony_ci struct attribute *attr_gen[8]; 648c2ecf20Sopenharmony_ci struct attribute_group grp; 658c2ecf20Sopenharmony_ci int created_ok; 668c2ecf20Sopenharmony_ci char name[80]; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct pvr2_sysfs_class { 708c2ecf20Sopenharmony_ci struct class class; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic ssize_t show_name(struct device *class_dev, 748c2ecf20Sopenharmony_ci struct device_attribute *attr, 758c2ecf20Sopenharmony_ci char *buf) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 788c2ecf20Sopenharmony_ci const char *name; 798c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name); 808c2ecf20Sopenharmony_ci name = pvr2_ctrl_get_desc(cip->cptr); 818c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s", 828c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, name); 838c2ecf20Sopenharmony_ci if (!name) return -EINVAL; 848c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", name); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic ssize_t show_type(struct device *class_dev, 888c2ecf20Sopenharmony_ci struct device_attribute *attr, 898c2ecf20Sopenharmony_ci char *buf) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 928c2ecf20Sopenharmony_ci const char *name; 938c2ecf20Sopenharmony_ci enum pvr2_ctl_type tp; 948c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type); 958c2ecf20Sopenharmony_ci tp = pvr2_ctrl_get_type(cip->cptr); 968c2ecf20Sopenharmony_ci switch (tp) { 978c2ecf20Sopenharmony_ci case pvr2_ctl_int: name = "integer"; break; 988c2ecf20Sopenharmony_ci case pvr2_ctl_enum: name = "enum"; break; 998c2ecf20Sopenharmony_ci case pvr2_ctl_bitmask: name = "bitmask"; break; 1008c2ecf20Sopenharmony_ci case pvr2_ctl_bool: name = "boolean"; break; 1018c2ecf20Sopenharmony_ci default: name = "?"; break; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", 1048c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, name); 1058c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", name); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic ssize_t show_min(struct device *class_dev, 1098c2ecf20Sopenharmony_ci struct device_attribute *attr, 1108c2ecf20Sopenharmony_ci char *buf) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1138c2ecf20Sopenharmony_ci long val; 1148c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min); 1158c2ecf20Sopenharmony_ci val = pvr2_ctrl_get_min(cip->cptr); 1168c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld", 1178c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, val); 1188c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%ld\n", val); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic ssize_t show_max(struct device *class_dev, 1228c2ecf20Sopenharmony_ci struct device_attribute *attr, 1238c2ecf20Sopenharmony_ci char *buf) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1268c2ecf20Sopenharmony_ci long val; 1278c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max); 1288c2ecf20Sopenharmony_ci val = pvr2_ctrl_get_max(cip->cptr); 1298c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld", 1308c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, val); 1318c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%ld\n", val); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic ssize_t show_def(struct device *class_dev, 1358c2ecf20Sopenharmony_ci struct device_attribute *attr, 1368c2ecf20Sopenharmony_ci char *buf) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1398c2ecf20Sopenharmony_ci int val; 1408c2ecf20Sopenharmony_ci int ret; 1418c2ecf20Sopenharmony_ci unsigned int cnt = 0; 1428c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def); 1438c2ecf20Sopenharmony_ci ret = pvr2_ctrl_get_def(cip->cptr, &val); 1448c2ecf20Sopenharmony_ci if (ret < 0) return ret; 1458c2ecf20Sopenharmony_ci ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, 1468c2ecf20Sopenharmony_ci buf, PAGE_SIZE - 1, &cnt); 1478c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %.*s (%d)", 1488c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, cnt, buf, val); 1498c2ecf20Sopenharmony_ci buf[cnt] = '\n'; 1508c2ecf20Sopenharmony_ci return cnt + 1; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic ssize_t show_val_norm(struct device *class_dev, 1548c2ecf20Sopenharmony_ci struct device_attribute *attr, 1558c2ecf20Sopenharmony_ci char *buf) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1588c2ecf20Sopenharmony_ci int val; 1598c2ecf20Sopenharmony_ci int ret; 1608c2ecf20Sopenharmony_ci unsigned int cnt = 0; 1618c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); 1628c2ecf20Sopenharmony_ci ret = pvr2_ctrl_get_value(cip->cptr, &val); 1638c2ecf20Sopenharmony_ci if (ret < 0) return ret; 1648c2ecf20Sopenharmony_ci ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val, 1658c2ecf20Sopenharmony_ci buf, PAGE_SIZE - 1, &cnt); 1668c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", 1678c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, cnt, buf, val); 1688c2ecf20Sopenharmony_ci buf[cnt] = '\n'; 1698c2ecf20Sopenharmony_ci return cnt+1; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic ssize_t show_val_custom(struct device *class_dev, 1738c2ecf20Sopenharmony_ci struct device_attribute *attr, 1748c2ecf20Sopenharmony_ci char *buf) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1778c2ecf20Sopenharmony_ci int val; 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci unsigned int cnt = 0; 1808c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); 1818c2ecf20Sopenharmony_ci ret = pvr2_ctrl_get_value(cip->cptr, &val); 1828c2ecf20Sopenharmony_ci if (ret < 0) return ret; 1838c2ecf20Sopenharmony_ci ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val, 1848c2ecf20Sopenharmony_ci buf, PAGE_SIZE - 1, &cnt); 1858c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", 1868c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, cnt, buf, val); 1878c2ecf20Sopenharmony_ci buf[cnt] = '\n'; 1888c2ecf20Sopenharmony_ci return cnt+1; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic ssize_t show_enum(struct device *class_dev, 1928c2ecf20Sopenharmony_ci struct device_attribute *attr, 1938c2ecf20Sopenharmony_ci char *buf) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 1968c2ecf20Sopenharmony_ci long val; 1978c2ecf20Sopenharmony_ci unsigned int bcnt, ccnt, ecnt; 1988c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum); 1998c2ecf20Sopenharmony_ci ecnt = pvr2_ctrl_get_cnt(cip->cptr); 2008c2ecf20Sopenharmony_ci bcnt = 0; 2018c2ecf20Sopenharmony_ci for (val = 0; val < ecnt; val++) { 2028c2ecf20Sopenharmony_ci pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt, 2038c2ecf20Sopenharmony_ci PAGE_SIZE - bcnt, &ccnt); 2048c2ecf20Sopenharmony_ci if (!ccnt) continue; 2058c2ecf20Sopenharmony_ci bcnt += ccnt; 2068c2ecf20Sopenharmony_ci if (bcnt >= PAGE_SIZE) break; 2078c2ecf20Sopenharmony_ci buf[bcnt] = '\n'; 2088c2ecf20Sopenharmony_ci bcnt++; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)", 2118c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id); 2128c2ecf20Sopenharmony_ci return bcnt; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic ssize_t show_bits(struct device *class_dev, 2168c2ecf20Sopenharmony_ci struct device_attribute *attr, 2178c2ecf20Sopenharmony_ci char *buf) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 2208c2ecf20Sopenharmony_ci int valid_bits, msk; 2218c2ecf20Sopenharmony_ci unsigned int bcnt, ccnt; 2228c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits); 2238c2ecf20Sopenharmony_ci valid_bits = pvr2_ctrl_get_mask(cip->cptr); 2248c2ecf20Sopenharmony_ci bcnt = 0; 2258c2ecf20Sopenharmony_ci for (msk = 1; valid_bits; msk <<= 1) { 2268c2ecf20Sopenharmony_ci if (!(msk & valid_bits)) continue; 2278c2ecf20Sopenharmony_ci valid_bits &= ~msk; 2288c2ecf20Sopenharmony_ci pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt, 2298c2ecf20Sopenharmony_ci PAGE_SIZE - bcnt, &ccnt); 2308c2ecf20Sopenharmony_ci bcnt += ccnt; 2318c2ecf20Sopenharmony_ci if (bcnt >= PAGE_SIZE) break; 2328c2ecf20Sopenharmony_ci buf[bcnt] = '\n'; 2338c2ecf20Sopenharmony_ci bcnt++; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)", 2368c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id); 2378c2ecf20Sopenharmony_ci return bcnt; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl, 2418c2ecf20Sopenharmony_ci const char *buf,unsigned int count) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci int ret; 2448c2ecf20Sopenharmony_ci int mask,val; 2458c2ecf20Sopenharmony_ci if (customfl) { 2468c2ecf20Sopenharmony_ci ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count, 2478c2ecf20Sopenharmony_ci &mask, &val); 2488c2ecf20Sopenharmony_ci } else { 2498c2ecf20Sopenharmony_ci ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count, 2508c2ecf20Sopenharmony_ci &mask, &val); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci if (ret < 0) return ret; 2538c2ecf20Sopenharmony_ci ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val); 2548c2ecf20Sopenharmony_ci pvr2_hdw_commit_ctl(cip->chptr->channel.hdw); 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic ssize_t store_val_norm(struct device *class_dev, 2598c2ecf20Sopenharmony_ci struct device_attribute *attr, 2608c2ecf20Sopenharmony_ci const char *buf, size_t count) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 2638c2ecf20Sopenharmony_ci int ret; 2648c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val); 2658c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"", 2668c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, (int)count, buf); 2678c2ecf20Sopenharmony_ci ret = store_val_any(cip, 0, buf, count); 2688c2ecf20Sopenharmony_ci if (!ret) ret = count; 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic ssize_t store_val_custom(struct device *class_dev, 2738c2ecf20Sopenharmony_ci struct device_attribute *attr, 2748c2ecf20Sopenharmony_ci const char *buf, size_t count) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom); 2798c2ecf20Sopenharmony_ci pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"", 2808c2ecf20Sopenharmony_ci cip->chptr, cip->ctl_id, (int)count, buf); 2818c2ecf20Sopenharmony_ci ret = store_val_any(cip, 1, buf, count); 2828c2ecf20Sopenharmony_ci if (!ret) ret = count; 2838c2ecf20Sopenharmony_ci return ret; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip; 2898c2ecf20Sopenharmony_ci struct pvr2_ctrl *cptr; 2908c2ecf20Sopenharmony_ci unsigned int cnt,acnt; 2918c2ecf20Sopenharmony_ci int ret; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); 2948c2ecf20Sopenharmony_ci if (!cptr) return; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cip = kzalloc(sizeof(*cip),GFP_KERNEL); 2978c2ecf20Sopenharmony_ci if (!cip) return; 2988c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci cip->cptr = cptr; 3018c2ecf20Sopenharmony_ci cip->ctl_id = ctl_id; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci cip->chptr = sfp; 3048c2ecf20Sopenharmony_ci cip->item_next = NULL; 3058c2ecf20Sopenharmony_ci if (sfp->item_last) { 3068c2ecf20Sopenharmony_ci sfp->item_last->item_next = cip; 3078c2ecf20Sopenharmony_ci } else { 3088c2ecf20Sopenharmony_ci sfp->item_first = cip; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci sfp->item_last = cip; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_name.attr); 3138c2ecf20Sopenharmony_ci cip->attr_name.attr.name = "name"; 3148c2ecf20Sopenharmony_ci cip->attr_name.attr.mode = S_IRUGO; 3158c2ecf20Sopenharmony_ci cip->attr_name.show = show_name; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_type.attr); 3188c2ecf20Sopenharmony_ci cip->attr_type.attr.name = "type"; 3198c2ecf20Sopenharmony_ci cip->attr_type.attr.mode = S_IRUGO; 3208c2ecf20Sopenharmony_ci cip->attr_type.show = show_type; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_min.attr); 3238c2ecf20Sopenharmony_ci cip->attr_min.attr.name = "min_val"; 3248c2ecf20Sopenharmony_ci cip->attr_min.attr.mode = S_IRUGO; 3258c2ecf20Sopenharmony_ci cip->attr_min.show = show_min; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_max.attr); 3288c2ecf20Sopenharmony_ci cip->attr_max.attr.name = "max_val"; 3298c2ecf20Sopenharmony_ci cip->attr_max.attr.mode = S_IRUGO; 3308c2ecf20Sopenharmony_ci cip->attr_max.show = show_max; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_def.attr); 3338c2ecf20Sopenharmony_ci cip->attr_def.attr.name = "def_val"; 3348c2ecf20Sopenharmony_ci cip->attr_def.attr.mode = S_IRUGO; 3358c2ecf20Sopenharmony_ci cip->attr_def.show = show_def; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_val.attr); 3388c2ecf20Sopenharmony_ci cip->attr_val.attr.name = "cur_val"; 3398c2ecf20Sopenharmony_ci cip->attr_val.attr.mode = S_IRUGO; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_custom.attr); 3428c2ecf20Sopenharmony_ci cip->attr_custom.attr.name = "custom_val"; 3438c2ecf20Sopenharmony_ci cip->attr_custom.attr.mode = S_IRUGO; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_enum.attr); 3468c2ecf20Sopenharmony_ci cip->attr_enum.attr.name = "enum_val"; 3478c2ecf20Sopenharmony_ci cip->attr_enum.attr.mode = S_IRUGO; 3488c2ecf20Sopenharmony_ci cip->attr_enum.show = show_enum; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci sysfs_attr_init(&cip->attr_bits.attr); 3518c2ecf20Sopenharmony_ci cip->attr_bits.attr.name = "bit_val"; 3528c2ecf20Sopenharmony_ci cip->attr_bits.attr.mode = S_IRUGO; 3538c2ecf20Sopenharmony_ci cip->attr_bits.show = show_bits; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (pvr2_ctrl_is_writable(cptr)) { 3568c2ecf20Sopenharmony_ci cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; 3578c2ecf20Sopenharmony_ci cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci acnt = 0; 3618c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_name.attr; 3628c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_type.attr; 3638c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_val.attr; 3648c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_def.attr; 3658c2ecf20Sopenharmony_ci cip->attr_val.show = show_val_norm; 3668c2ecf20Sopenharmony_ci cip->attr_val.store = store_val_norm; 3678c2ecf20Sopenharmony_ci if (pvr2_ctrl_has_custom_symbols(cptr)) { 3688c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_custom.attr; 3698c2ecf20Sopenharmony_ci cip->attr_custom.show = show_val_custom; 3708c2ecf20Sopenharmony_ci cip->attr_custom.store = store_val_custom; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci switch (pvr2_ctrl_get_type(cptr)) { 3738c2ecf20Sopenharmony_ci case pvr2_ctl_enum: 3748c2ecf20Sopenharmony_ci // Control is an enumeration 3758c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_enum.attr; 3768c2ecf20Sopenharmony_ci break; 3778c2ecf20Sopenharmony_ci case pvr2_ctl_int: 3788c2ecf20Sopenharmony_ci // Control is an integer 3798c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_min.attr; 3808c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_max.attr; 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci case pvr2_ctl_bitmask: 3838c2ecf20Sopenharmony_ci // Control is an bitmask 3848c2ecf20Sopenharmony_ci cip->attr_gen[acnt++] = &cip->attr_bits.attr; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci default: break; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s", 3908c2ecf20Sopenharmony_ci pvr2_ctrl_get_name(cptr)); 3918c2ecf20Sopenharmony_ci cip->name[cnt] = 0; 3928c2ecf20Sopenharmony_ci cip->grp.name = cip->name; 3938c2ecf20Sopenharmony_ci cip->grp.attrs = cip->attr_gen; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); 3968c2ecf20Sopenharmony_ci if (ret) { 3978c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 3988c2ecf20Sopenharmony_ci "sysfs_create_group error: %d", 3998c2ecf20Sopenharmony_ci ret); 4008c2ecf20Sopenharmony_ci return; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci cip->created_ok = !0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 4068c2ecf20Sopenharmony_cistatic ssize_t debuginfo_show(struct device *, struct device_attribute *, 4078c2ecf20Sopenharmony_ci char *); 4088c2ecf20Sopenharmony_cistatic ssize_t debugcmd_show(struct device *, struct device_attribute *, 4098c2ecf20Sopenharmony_ci char *); 4108c2ecf20Sopenharmony_cistatic ssize_t debugcmd_store(struct device *, struct device_attribute *, 4118c2ecf20Sopenharmony_ci const char *, size_t count); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct pvr2_sysfs_debugifc *dip; 4168c2ecf20Sopenharmony_ci int ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci dip = kzalloc(sizeof(*dip),GFP_KERNEL); 4198c2ecf20Sopenharmony_ci if (!dip) return; 4208c2ecf20Sopenharmony_ci sysfs_attr_init(&dip->attr_debugcmd.attr); 4218c2ecf20Sopenharmony_ci dip->attr_debugcmd.attr.name = "debugcmd"; 4228c2ecf20Sopenharmony_ci dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; 4238c2ecf20Sopenharmony_ci dip->attr_debugcmd.show = debugcmd_show; 4248c2ecf20Sopenharmony_ci dip->attr_debugcmd.store = debugcmd_store; 4258c2ecf20Sopenharmony_ci sysfs_attr_init(&dip->attr_debuginfo.attr); 4268c2ecf20Sopenharmony_ci dip->attr_debuginfo.attr.name = "debuginfo"; 4278c2ecf20Sopenharmony_ci dip->attr_debuginfo.attr.mode = S_IRUGO; 4288c2ecf20Sopenharmony_ci dip->attr_debuginfo.show = debuginfo_show; 4298c2ecf20Sopenharmony_ci sfp->debugifc = dip; 4308c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); 4318c2ecf20Sopenharmony_ci if (ret < 0) { 4328c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 4338c2ecf20Sopenharmony_ci "device_create_file error: %d", 4348c2ecf20Sopenharmony_ci ret); 4358c2ecf20Sopenharmony_ci } else { 4368c2ecf20Sopenharmony_ci dip->debugcmd_created_ok = !0; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); 4398c2ecf20Sopenharmony_ci if (ret < 0) { 4408c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 4418c2ecf20Sopenharmony_ci "device_create_file error: %d", 4428c2ecf20Sopenharmony_ci ret); 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci dip->debuginfo_created_ok = !0; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci if (!sfp->debugifc) return; 4528c2ecf20Sopenharmony_ci if (sfp->debugifc->debuginfo_created_ok) { 4538c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 4548c2ecf20Sopenharmony_ci &sfp->debugifc->attr_debuginfo); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci if (sfp->debugifc->debugcmd_created_ok) { 4578c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 4588c2ecf20Sopenharmony_ci &sfp->debugifc->attr_debugcmd); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci kfree(sfp->debugifc); 4618c2ecf20Sopenharmony_ci sfp->debugifc = NULL; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci unsigned int idx,cnt; 4698c2ecf20Sopenharmony_ci cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw); 4708c2ecf20Sopenharmony_ci for (idx = 0; idx < cnt; idx++) { 4718c2ecf20Sopenharmony_ci pvr2_sysfs_add_control(sfp,idx); 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct pvr2_sysfs_ctl_item *cip1,*cip2; 4798c2ecf20Sopenharmony_ci for (cip1 = sfp->item_first; cip1; cip1 = cip2) { 4808c2ecf20Sopenharmony_ci cip2 = cip1->item_next; 4818c2ecf20Sopenharmony_ci if (cip1->created_ok) { 4828c2ecf20Sopenharmony_ci sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); 4858c2ecf20Sopenharmony_ci kfree(cip1); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void pvr2_sysfs_class_release(struct class *class) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct pvr2_sysfs_class *clp; 4938c2ecf20Sopenharmony_ci clp = container_of(class,struct pvr2_sysfs_class,class); 4948c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); 4958c2ecf20Sopenharmony_ci kfree(clp); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic void pvr2_sysfs_release(struct device *class_dev) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); 5028c2ecf20Sopenharmony_ci kfree(class_dev); 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic void class_dev_destroy(struct pvr2_sysfs *sfp) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct device *dev; 5098c2ecf20Sopenharmony_ci if (!sfp->class_dev) return; 5108c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 5118c2ecf20Sopenharmony_ci pvr2_sysfs_tear_down_debugifc(sfp); 5128c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 5138c2ecf20Sopenharmony_ci pvr2_sysfs_tear_down_controls(sfp); 5148c2ecf20Sopenharmony_ci if (sfp->hdw_desc_created_ok) { 5158c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5168c2ecf20Sopenharmony_ci &sfp->attr_hdw_desc); 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci if (sfp->hdw_name_created_ok) { 5198c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5208c2ecf20Sopenharmony_ci &sfp->attr_hdw_name); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci if (sfp->bus_info_created_ok) { 5238c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5248c2ecf20Sopenharmony_ci &sfp->attr_bus_info); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci if (sfp->v4l_minor_number_created_ok) { 5278c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5288c2ecf20Sopenharmony_ci &sfp->attr_v4l_minor_number); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci if (sfp->v4l_radio_minor_number_created_ok) { 5318c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5328c2ecf20Sopenharmony_ci &sfp->attr_v4l_radio_minor_number); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci if (sfp->unit_number_created_ok) { 5358c2ecf20Sopenharmony_ci device_remove_file(sfp->class_dev, 5368c2ecf20Sopenharmony_ci &sfp->attr_unit_number); 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); 5398c2ecf20Sopenharmony_ci dev_set_drvdata(sfp->class_dev, NULL); 5408c2ecf20Sopenharmony_ci dev = sfp->class_dev->parent; 5418c2ecf20Sopenharmony_ci sfp->class_dev->parent = NULL; 5428c2ecf20Sopenharmony_ci put_device(dev); 5438c2ecf20Sopenharmony_ci device_unregister(sfp->class_dev); 5448c2ecf20Sopenharmony_ci sfp->class_dev = NULL; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic ssize_t v4l_minor_number_show(struct device *class_dev, 5498c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 5528c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 5538c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 5548c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%d\n", 5558c2ecf20Sopenharmony_ci pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, 5568c2ecf20Sopenharmony_ci pvr2_v4l_type_video)); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic ssize_t bus_info_show(struct device *class_dev, 5618c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 5648c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 5658c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 5668c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%s\n", 5678c2ecf20Sopenharmony_ci pvr2_hdw_get_bus_info(sfp->channel.hdw)); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic ssize_t hdw_name_show(struct device *class_dev, 5728c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 5758c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 5768c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 5778c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%s\n", 5788c2ecf20Sopenharmony_ci pvr2_hdw_get_type(sfp->channel.hdw)); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic ssize_t hdw_desc_show(struct device *class_dev, 5838c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 5868c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 5878c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 5888c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%s\n", 5898c2ecf20Sopenharmony_ci pvr2_hdw_get_desc(sfp->channel.hdw)); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic ssize_t v4l_radio_minor_number_show(struct device *class_dev, 5948c2ecf20Sopenharmony_ci struct device_attribute *attr, 5958c2ecf20Sopenharmony_ci char *buf) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 5988c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 5998c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 6008c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%d\n", 6018c2ecf20Sopenharmony_ci pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, 6028c2ecf20Sopenharmony_ci pvr2_v4l_type_radio)); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic ssize_t unit_number_show(struct device *class_dev, 6078c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 6108c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 6118c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 6128c2ecf20Sopenharmony_ci return scnprintf(buf,PAGE_SIZE,"%d\n", 6138c2ecf20Sopenharmony_ci pvr2_hdw_get_unit_number(sfp->channel.hdw)); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic void class_dev_create(struct pvr2_sysfs *sfp, 6188c2ecf20Sopenharmony_ci struct pvr2_sysfs_class *class_ptr) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci struct usb_device *usb_dev; 6218c2ecf20Sopenharmony_ci struct device *class_dev; 6228c2ecf20Sopenharmony_ci int ret; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); 6258c2ecf20Sopenharmony_ci if (!usb_dev) return; 6268c2ecf20Sopenharmony_ci class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL); 6278c2ecf20Sopenharmony_ci if (!class_dev) return; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci class_dev->class = &class_ptr->class; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci dev_set_name(class_dev, "%s", 6348c2ecf20Sopenharmony_ci pvr2_hdw_get_device_identifier(sfp->channel.hdw)); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci class_dev->parent = get_device(&usb_dev->dev); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci sfp->class_dev = class_dev; 6398c2ecf20Sopenharmony_ci dev_set_drvdata(class_dev, sfp); 6408c2ecf20Sopenharmony_ci ret = device_register(class_dev); 6418c2ecf20Sopenharmony_ci if (ret) { 6428c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6438c2ecf20Sopenharmony_ci "device_register failed"); 6448c2ecf20Sopenharmony_ci put_device(class_dev); 6458c2ecf20Sopenharmony_ci return; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_v4l_minor_number.attr); 6498c2ecf20Sopenharmony_ci sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; 6508c2ecf20Sopenharmony_ci sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; 6518c2ecf20Sopenharmony_ci sfp->attr_v4l_minor_number.show = v4l_minor_number_show; 6528c2ecf20Sopenharmony_ci sfp->attr_v4l_minor_number.store = NULL; 6538c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev, 6548c2ecf20Sopenharmony_ci &sfp->attr_v4l_minor_number); 6558c2ecf20Sopenharmony_ci if (ret < 0) { 6568c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6578c2ecf20Sopenharmony_ci "device_create_file error: %d", 6588c2ecf20Sopenharmony_ci ret); 6598c2ecf20Sopenharmony_ci } else { 6608c2ecf20Sopenharmony_ci sfp->v4l_minor_number_created_ok = !0; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr); 6648c2ecf20Sopenharmony_ci sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; 6658c2ecf20Sopenharmony_ci sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; 6668c2ecf20Sopenharmony_ci sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; 6678c2ecf20Sopenharmony_ci sfp->attr_v4l_radio_minor_number.store = NULL; 6688c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev, 6698c2ecf20Sopenharmony_ci &sfp->attr_v4l_radio_minor_number); 6708c2ecf20Sopenharmony_ci if (ret < 0) { 6718c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6728c2ecf20Sopenharmony_ci "device_create_file error: %d", 6738c2ecf20Sopenharmony_ci ret); 6748c2ecf20Sopenharmony_ci } else { 6758c2ecf20Sopenharmony_ci sfp->v4l_radio_minor_number_created_ok = !0; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_unit_number.attr); 6798c2ecf20Sopenharmony_ci sfp->attr_unit_number.attr.name = "unit_number"; 6808c2ecf20Sopenharmony_ci sfp->attr_unit_number.attr.mode = S_IRUGO; 6818c2ecf20Sopenharmony_ci sfp->attr_unit_number.show = unit_number_show; 6828c2ecf20Sopenharmony_ci sfp->attr_unit_number.store = NULL; 6838c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); 6848c2ecf20Sopenharmony_ci if (ret < 0) { 6858c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 6868c2ecf20Sopenharmony_ci "device_create_file error: %d", 6878c2ecf20Sopenharmony_ci ret); 6888c2ecf20Sopenharmony_ci } else { 6898c2ecf20Sopenharmony_ci sfp->unit_number_created_ok = !0; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_bus_info.attr); 6938c2ecf20Sopenharmony_ci sfp->attr_bus_info.attr.name = "bus_info_str"; 6948c2ecf20Sopenharmony_ci sfp->attr_bus_info.attr.mode = S_IRUGO; 6958c2ecf20Sopenharmony_ci sfp->attr_bus_info.show = bus_info_show; 6968c2ecf20Sopenharmony_ci sfp->attr_bus_info.store = NULL; 6978c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev, 6988c2ecf20Sopenharmony_ci &sfp->attr_bus_info); 6998c2ecf20Sopenharmony_ci if (ret < 0) { 7008c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 7018c2ecf20Sopenharmony_ci "device_create_file error: %d", 7028c2ecf20Sopenharmony_ci ret); 7038c2ecf20Sopenharmony_ci } else { 7048c2ecf20Sopenharmony_ci sfp->bus_info_created_ok = !0; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_hdw_name.attr); 7088c2ecf20Sopenharmony_ci sfp->attr_hdw_name.attr.name = "device_hardware_type"; 7098c2ecf20Sopenharmony_ci sfp->attr_hdw_name.attr.mode = S_IRUGO; 7108c2ecf20Sopenharmony_ci sfp->attr_hdw_name.show = hdw_name_show; 7118c2ecf20Sopenharmony_ci sfp->attr_hdw_name.store = NULL; 7128c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev, 7138c2ecf20Sopenharmony_ci &sfp->attr_hdw_name); 7148c2ecf20Sopenharmony_ci if (ret < 0) { 7158c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 7168c2ecf20Sopenharmony_ci "device_create_file error: %d", 7178c2ecf20Sopenharmony_ci ret); 7188c2ecf20Sopenharmony_ci } else { 7198c2ecf20Sopenharmony_ci sfp->hdw_name_created_ok = !0; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci sysfs_attr_init(&sfp->attr_hdw_desc.attr); 7238c2ecf20Sopenharmony_ci sfp->attr_hdw_desc.attr.name = "device_hardware_description"; 7248c2ecf20Sopenharmony_ci sfp->attr_hdw_desc.attr.mode = S_IRUGO; 7258c2ecf20Sopenharmony_ci sfp->attr_hdw_desc.show = hdw_desc_show; 7268c2ecf20Sopenharmony_ci sfp->attr_hdw_desc.store = NULL; 7278c2ecf20Sopenharmony_ci ret = device_create_file(sfp->class_dev, 7288c2ecf20Sopenharmony_ci &sfp->attr_hdw_desc); 7298c2ecf20Sopenharmony_ci if (ret < 0) { 7308c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 7318c2ecf20Sopenharmony_ci "device_create_file error: %d", 7328c2ecf20Sopenharmony_ci ret); 7338c2ecf20Sopenharmony_ci } else { 7348c2ecf20Sopenharmony_ci sfp->hdw_desc_created_ok = !0; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci pvr2_sysfs_add_controls(sfp); 7388c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 7398c2ecf20Sopenharmony_ci pvr2_sysfs_add_debugifc(sfp); 7408c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void pvr2_sysfs_internal_check(struct pvr2_channel *chp) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 7478c2ecf20Sopenharmony_ci sfp = container_of(chp,struct pvr2_sysfs,channel); 7488c2ecf20Sopenharmony_ci if (!sfp->channel.mc_head->disconnect_flag) return; 7498c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp); 7508c2ecf20Sopenharmony_ci class_dev_destroy(sfp); 7518c2ecf20Sopenharmony_ci pvr2_channel_done(&sfp->channel); 7528c2ecf20Sopenharmony_ci kfree(sfp); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistruct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, 7578c2ecf20Sopenharmony_ci struct pvr2_sysfs_class *class_ptr) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 7608c2ecf20Sopenharmony_ci sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); 7618c2ecf20Sopenharmony_ci if (!sfp) return sfp; 7628c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); 7638c2ecf20Sopenharmony_ci pvr2_channel_init(&sfp->channel,mp); 7648c2ecf20Sopenharmony_ci sfp->channel.check_func = pvr2_sysfs_internal_check; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci class_dev_create(sfp,class_ptr); 7678c2ecf20Sopenharmony_ci return sfp; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistruct pvr2_sysfs_class *pvr2_sysfs_class_create(void) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci struct pvr2_sysfs_class *clp; 7758c2ecf20Sopenharmony_ci clp = kzalloc(sizeof(*clp),GFP_KERNEL); 7768c2ecf20Sopenharmony_ci if (!clp) return clp; 7778c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p", 7788c2ecf20Sopenharmony_ci clp); 7798c2ecf20Sopenharmony_ci clp->class.name = "pvrusb2"; 7808c2ecf20Sopenharmony_ci clp->class.class_release = pvr2_sysfs_class_release; 7818c2ecf20Sopenharmony_ci clp->class.dev_release = pvr2_sysfs_release; 7828c2ecf20Sopenharmony_ci if (class_register(&clp->class)) { 7838c2ecf20Sopenharmony_ci pvr2_sysfs_trace( 7848c2ecf20Sopenharmony_ci "Registration failed for pvr2_sysfs_class id=%p",clp); 7858c2ecf20Sopenharmony_ci kfree(clp); 7868c2ecf20Sopenharmony_ci clp = NULL; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci return clp; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_civoid pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); 7958c2ecf20Sopenharmony_ci if (clp) 7968c2ecf20Sopenharmony_ci class_unregister(&clp->class); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC 8018c2ecf20Sopenharmony_cistatic ssize_t debuginfo_show(struct device *class_dev, 8028c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8038c2ecf20Sopenharmony_ci{ 8048c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 8058c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 8068c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 8078c2ecf20Sopenharmony_ci pvr2_hdw_trigger_module_log(sfp->channel.hdw); 8088c2ecf20Sopenharmony_ci return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic ssize_t debugcmd_show(struct device *class_dev, 8138c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 8168c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 8178c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 8188c2ecf20Sopenharmony_ci return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic ssize_t debugcmd_store(struct device *class_dev, 8238c2ecf20Sopenharmony_ci struct device_attribute *attr, 8248c2ecf20Sopenharmony_ci const char *buf, size_t count) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci struct pvr2_sysfs *sfp; 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci sfp = dev_get_drvdata(class_dev); 8308c2ecf20Sopenharmony_ci if (!sfp) return -EINVAL; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); 8338c2ecf20Sopenharmony_ci if (ret < 0) return ret; 8348c2ecf20Sopenharmony_ci return count; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ 837