📄 pvrusb2-sysfs.c
字号:
/* * * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <linux/string.h>#include <linux/slab.h>#include <asm/semaphore.h>#include "pvrusb2-sysfs.h"#include "pvrusb2-hdw.h"#include "pvrusb2-debug.h"#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC#include "pvrusb2-debugifc.h"#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)struct pvr2_sysfs { struct pvr2_channel channel; struct device *class_dev;#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC struct pvr2_sysfs_debugifc *debugifc;#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ struct pvr2_sysfs_ctl_item *item_first; struct pvr2_sysfs_ctl_item *item_last; struct device_attribute attr_v4l_minor_number; struct device_attribute attr_v4l_radio_minor_number; struct device_attribute attr_unit_number; struct device_attribute attr_bus_info; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; int bus_info_created_ok;};#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFCstruct pvr2_sysfs_debugifc { struct device_attribute attr_debugcmd; struct device_attribute attr_debuginfo; int debugcmd_created_ok; int debuginfo_created_ok;};#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */struct pvr2_sysfs_ctl_item { struct device_attribute attr_name; struct device_attribute attr_type; struct device_attribute attr_min; struct device_attribute attr_max; struct device_attribute attr_enum; struct device_attribute attr_bits; struct device_attribute attr_val; struct device_attribute attr_custom; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; struct attribute *attr_gen[7]; struct attribute_group grp; int created_ok; char name[80];};struct pvr2_sysfs_class { struct class class;};static ssize_t show_name(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; name = pvr2_ctrl_get_desc(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name); if (!name) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n",name);}static ssize_t show_type(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; enum pvr2_ctl_type tp; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; tp = pvr2_ctrl_get_type(cptr); switch (tp) { case pvr2_ctl_int: name = "integer"; break; case pvr2_ctl_enum: name = "enum"; break; case pvr2_ctl_bitmask: name = "bitmask"; break; case pvr2_ctl_bool: name = "boolean"; break; default: name = "?"; break; } pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name); if (!name) return -EINVAL; return scnprintf(buf,PAGE_SIZE,"%s\n",name);}static ssize_t show_min(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; val = pvr2_ctrl_get_min(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val); return scnprintf(buf,PAGE_SIZE,"%ld\n",val);}static ssize_t show_max(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; val = pvr2_ctrl_get_max(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val); return scnprintf(buf,PAGE_SIZE,"%ld\n",val);}static ssize_t show_val_norm(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; ret = pvr2_ctrl_get_value(cptr,&val); if (ret < 0) return ret; ret = pvr2_ctrl_value_to_sym(cptr,~0,val, buf,PAGE_SIZE-1,&cnt); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", sfp,id,cnt,buf,val); buf[cnt] = '\n'; return cnt+1;}static ssize_t show_val_custom(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val,ret; unsigned int cnt = 0; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; ret = pvr2_ctrl_get_value(cptr,&val); if (ret < 0) return ret; ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val, buf,PAGE_SIZE-1,&cnt); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", sfp,id,cnt,buf,val); buf[cnt] = '\n'; return cnt+1;}static ssize_t show_enum(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; long val; unsigned int bcnt,ccnt,ecnt; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; ecnt = pvr2_ctrl_get_cnt(cptr); bcnt = 0; for (val = 0; val < ecnt; val++) { pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); if (!ccnt) continue; bcnt += ccnt; if (bcnt >= PAGE_SIZE) break; buf[bcnt] = '\n'; bcnt++; } pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id); return bcnt;}static ssize_t show_bits(int id,struct device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int valid_bits,msk; unsigned int bcnt,ccnt; sfp = (struct pvr2_sysfs *)class_dev->driver_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!cptr) return -EINVAL; valid_bits = pvr2_ctrl_get_mask(cptr); bcnt = 0; for (msk = 1; valid_bits; msk <<= 1) { if (!(msk & valid_bits)) continue; valid_bits &= ~msk; pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); bcnt += ccnt; if (bcnt >= PAGE_SIZE) break; buf[bcnt] = '\n'; bcnt++; } pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id); return bcnt;}static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, const char *buf,unsigned int count){ struct pvr2_ctrl *cptr; int ret; int mask,val; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (customfl) { ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val); } else { ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val); } if (ret < 0) return ret; ret = pvr2_ctrl_set_mask_value(cptr,mask,val); pvr2_hdw_commit_ctl(sfp->channel.hdw); return ret;}static ssize_t store_val_norm(int id,struct device *class_dev, const char *buf,size_t count){ struct pvr2_sysfs *sfp; int ret; sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,0,sfp,buf,count); if (!ret) ret = count; return ret;}static ssize_t store_val_custom(int id,struct device *class_dev, const char *buf,size_t count){ struct pvr2_sysfs *sfp; int ret; sfp = (struct pvr2_sysfs *)class_dev->driver_data; ret = store_val_any(id,1,sfp,buf,count); if (!ret) ret = count; return ret;}/* Mike Isely <isely@pobox.com> 30-April-2005 This next batch of horrible preprocessor hackery is needed because the kernel's device_attribute mechanism fails to pass the actual attribute through to the show / store functions, which means we have no way to package up any attribute-specific parameters, like for example the control id. So we work around this brain-damage by encoding the control id into the show / store functions themselves and pick the function based on the control id we're setting up. These macros try to ease the pain. Yuck.*/#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \static ssize_t sf_name##_##ctl_id(struct device *class_dev, \struct device_attribute *attr, char *buf) \{ return sf_name(ctl_id,class_dev,buf); }#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \static ssize_t sf_name##_##ctl_id(struct device *class_dev, \struct device_attribute *attr, const char *buf, size_t count) \{ return sf_name(ctl_id,class_dev,buf,count); }#define CREATE_BATCH(ctl_id) \CREATE_SHOW_INSTANCE(show_name,ctl_id) \CREATE_SHOW_INSTANCE(show_type,ctl_id) \CREATE_SHOW_INSTANCE(show_min,ctl_id) \CREATE_SHOW_INSTANCE(show_max,ctl_id) \CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \CREATE_SHOW_INSTANCE(show_enum,ctl_id) \CREATE_SHOW_INSTANCE(show_bits,ctl_id) \CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \CREATE_BATCH(0)CREATE_BATCH(1)CREATE_BATCH(2)CREATE_BATCH(3)CREATE_BATCH(4)CREATE_BATCH(5)CREATE_BATCH(6)CREATE_BATCH(7)CREATE_BATCH(8)CREATE_BATCH(9)CREATE_BATCH(10)CREATE_BATCH(11)CREATE_BATCH(12)CREATE_BATCH(13)CREATE_BATCH(14)CREATE_BATCH(15)CREATE_BATCH(16)CREATE_BATCH(17)CREATE_BATCH(18)CREATE_BATCH(19)CREATE_BATCH(20)CREATE_BATCH(21)CREATE_BATCH(22)CREATE_BATCH(23)CREATE_BATCH(24)CREATE_BATCH(25)CREATE_BATCH(26)CREATE_BATCH(27)CREATE_BATCH(28)CREATE_BATCH(29)CREATE_BATCH(30)CREATE_BATCH(31)CREATE_BATCH(32)CREATE_BATCH(33)CREATE_BATCH(34)CREATE_BATCH(35)CREATE_BATCH(36)CREATE_BATCH(37)CREATE_BATCH(38)CREATE_BATCH(39)CREATE_BATCH(40)CREATE_BATCH(41)CREATE_BATCH(42)CREATE_BATCH(43)CREATE_BATCH(44)CREATE_BATCH(45)CREATE_BATCH(46)CREATE_BATCH(47)CREATE_BATCH(48)CREATE_BATCH(49)CREATE_BATCH(50)CREATE_BATCH(51)CREATE_BATCH(52)CREATE_BATCH(53)CREATE_BATCH(54)CREATE_BATCH(55)CREATE_BATCH(56)CREATE_BATCH(57)CREATE_BATCH(58)CREATE_BATCH(59)struct pvr2_sysfs_func_set { ssize_t (*show_name)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_type)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_min)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_max)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_enum)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_bits)(struct device *, struct device_attribute *attr, char *); ssize_t (*show_val_norm)(struct device *, struct device_attribute *attr, char *); ssize_t (*store_val_norm)(struct device *, struct device_attribute *attr, const char *,size_t); ssize_t (*show_val_custom)(struct device *, struct device_attribute *attr, char *); ssize_t (*store_val_custom)(struct device *, struct device_attribute *attr, const char *,size_t);};#define INIT_BATCH(ctl_id) \[ctl_id] = { \ .show_name = show_name_##ctl_id, \ .show_type = show_type_##ctl_id, \ .show_min = show_min_##ctl_id, \ .show_max = show_max_##ctl_id, \ .show_enum = show_enum_##ctl_id, \ .show_bits = show_bits_##ctl_id, \ .show_val_norm = show_val_norm_##ctl_id, \ .store_val_norm = store_val_norm_##ctl_id, \ .show_val_custom = show_val_custom_##ctl_id, \ .store_val_custom = store_val_custom_##ctl_id, \} \static struct pvr2_sysfs_func_set funcs[] = { INIT_BATCH(0), INIT_BATCH(1), INIT_BATCH(2), INIT_BATCH(3), INIT_BATCH(4), INIT_BATCH(5), INIT_BATCH(6), INIT_BATCH(7), INIT_BATCH(8), INIT_BATCH(9), INIT_BATCH(10), INIT_BATCH(11), INIT_BATCH(12), INIT_BATCH(13), INIT_BATCH(14), INIT_BATCH(15), INIT_BATCH(16), INIT_BATCH(17), INIT_BATCH(18), INIT_BATCH(19), INIT_BATCH(20), INIT_BATCH(21), INIT_BATCH(22), INIT_BATCH(23), INIT_BATCH(24), INIT_BATCH(25), INIT_BATCH(26), INIT_BATCH(27), INIT_BATCH(28), INIT_BATCH(29), INIT_BATCH(30), INIT_BATCH(31), INIT_BATCH(32), INIT_BATCH(33), INIT_BATCH(34), INIT_BATCH(35), INIT_BATCH(36), INIT_BATCH(37), INIT_BATCH(38), INIT_BATCH(39), INIT_BATCH(40), INIT_BATCH(41), INIT_BATCH(42), INIT_BATCH(43), INIT_BATCH(44), INIT_BATCH(45), INIT_BATCH(46), INIT_BATCH(47), INIT_BATCH(48), INIT_BATCH(49), INIT_BATCH(50), INIT_BATCH(51), INIT_BATCH(52),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -