📄 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 "compat.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 class_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 sysfs_ops kops; struct kobj_type ktype; struct class_device_attribute attr_v4l_minor_number; struct class_device_attribute attr_unit_number;};#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFCstruct pvr2_sysfs_debugifc { struct class_device_attribute attr_debugcmd; struct class_device_attribute attr_debuginfo;};#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */struct pvr2_sysfs_ctl_item { struct class_device_attribute attr_name; struct class_device_attribute attr_min; struct class_device_attribute attr_max; struct class_device_attribute attr_enum; struct class_device_attribute attr_val; struct pvr2_ctrl *cptr; struct pvr2_sysfs *chptr; struct pvr2_sysfs_ctl_item *item_next; struct attribute *attr_gen[5]; struct attribute_group grp; char name[80];};struct pvr2_sysfs_class { struct class class;};static ssize_t show_name(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; const char *name; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(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_min(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; val = pvr2_ctrl_get_min_value(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %d",sfp,id,val); return scnprintf(buf,PAGE_SIZE,"%d\n",val);}static ssize_t show_max(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; val = pvr2_ctrl_get_max_value(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %d",sfp,id,val); return scnprintf(buf,PAGE_SIZE,"%d\n",val);}static ssize_t show_val_int(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; val = pvr2_ctrl_get_value(cptr); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_int(cid=%d) is %d", sfp,id,val); return scnprintf(buf,PAGE_SIZE,"%d\n",val);}static ssize_t show_val_enum(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int val; const char *name; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; val = pvr2_ctrl_get_value(cptr); name = pvr2_ctrl_get_value_name(cptr,val); pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_enum(cid=%d) is %s (%d)", sfp,id,name,val); return scnprintf(buf,PAGE_SIZE,"%s\n",name);}static ssize_t show_enum(int id,struct class_device *class_dev,char *buf){ struct pvr2_ctrl *cptr; struct pvr2_sysfs *sfp; int minval,maxval,val; const char *name; ssize_t cnt = 0; sfp = (struct pvr2_sysfs *)class_dev->class_data; if (!sfp) return -EINVAL; cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; minval = pvr2_ctrl_get_min_value(cptr); maxval = pvr2_ctrl_get_max_value(cptr); for (val = minval; val <= maxval; val++) { name = pvr2_ctrl_get_value_name(cptr,val); cnt += scnprintf(buf+cnt,PAGE_SIZE-cnt,"%s\n",name); } pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id); return cnt;}static int store_val_any(int id,struct pvr2_sysfs *sfp, const char *buf,unsigned int count){ struct pvr2_ctrl *cptr; int val,minval,maxval; int ch,ret; const char *nv; unsigned int nl; int negfl; /* Trim leading / trailing whitespace */ while (count) { ch = buf[0]; if ((ch > 32) && (ch < 127)) break; buf++; count--; } while (count) { ch = buf[count-1]; if ((ch > 32) && (ch < 127)) break; count--; } cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); if (!pvr2_ctrl_is_valid(cptr)) return -EINVAL; /* Is this an enum? Look for a string value */ minval = pvr2_ctrl_get_min_value(cptr); maxval = pvr2_ctrl_get_max_value(cptr); for (val = minval; val <= maxval; val++) { nv = pvr2_ctrl_get_value_name(cptr,val); if ((!nv) && (val == minval)) break; /* Not an enum */ pvr2_sysfs_trace("pvr2_sysfs(%p) trying ctl_id %d val %d", sfp,id,val); if (!nv) { pvr2_sysfs_trace("pvr2_sysfs(%p) no pointer",sfp); continue; } nl = strlen(nv); if (nl != count) { pvr2_sysfs_trace("pvr2_sysfs(%p) count mismatch" " %d != %d", sfp,count,nl); continue; } if (memcmp(buf,nv,nl)) { pvr2_sysfs_trace( "pvr2_sysfs(%p) name mismatch" " >>%.*s<< != >>%.*s<<", sfp,nl,buf,nl,nv); continue; } pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_any(cid=%d)" " is enum %s", sfp,id,nv); ret = pvr2_ctrl_set_value(cptr,val); pvr2_hdw_commit_ctl(sfp->channel.hdw); return 0; } if (val > minval) { pvr2_sysfs_trace( "pvr2_sysfs(%p) store_val_any(cid=%d)" " unmatched enum >>%.*s<<", sfp,id,count,buf); } /* Try to parse as a number */ negfl = 0; val = 0; if (count) { if (buf[0] == '-') { negfl = !0; buf++; count--; } else if (buf[0] == '+') { buf++; count--; } } while (count) { ch = buf[0]; if ((ch < '0') || (ch > '9')) break; val = val * 10; val += (ch - '0'); buf++; count--; } if (!count) { if (negfl) val = -val; pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_any(cid=%d)" " int is %d", sfp,id,val); ret = pvr2_ctrl_set_value(cptr,val); pvr2_hdw_commit_ctl(sfp->channel.hdw); return ret; } return -EINVAL;}static int store_val_multi(int id,struct pvr2_sysfs *sfp, const char *buf,unsigned int count){ unsigned int count2; int ret; while (count) { count2 = 0; while ((count2 < count) && (buf[count2] != '\n')) count2++; ret = store_val_any(id,sfp,buf,count2); if (ret < 0) return ret; if (count2 < count) count2++; buf += count2; count -= count2; } return 0;}static ssize_t store_val_int(int id,struct class_device *class_dev, const char *buf,size_t count){ struct pvr2_sysfs *sfp; int ret; sfp = (struct pvr2_sysfs *)class_dev->class_data; ret = store_val_multi(id,sfp,buf,count); if (!ret) ret = count; return ret;}static ssize_t store_val_enum(int id,struct class_device *class_dev, const char *buf,size_t count){ struct pvr2_sysfs *sfp; int ret; sfp = (struct pvr2_sysfs *)class_dev->class_data; ret = store_val_multi(id,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 class_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 class_device *class_dev,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 class_device *class_dev,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_min,ctl_id) \CREATE_SHOW_INSTANCE(show_max,ctl_id) \CREATE_SHOW_INSTANCE(show_val_int,ctl_id) \CREATE_SHOW_INSTANCE(show_val_enum,ctl_id) \CREATE_SHOW_INSTANCE(show_enum,ctl_id) \CREATE_STORE_INSTANCE(store_val_int,ctl_id) \CREATE_STORE_INSTANCE(store_val_enum,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)struct pvr2_sysfs_func_set { ssize_t (*show_name)(struct class_device *,char *); ssize_t (*show_min)(struct class_device *,char *); ssize_t (*show_max)(struct class_device *,char *); ssize_t (*show_enum)(struct class_device *,char *); ssize_t (*show_val_int)(struct class_device *,char *); ssize_t (*show_val_enum)(struct class_device *,char *); ssize_t (*store_val_int)(struct class_device *, const char *,size_t); ssize_t (*store_val_enum)(struct class_device *, const char *,size_t);};#define INIT_BATCH(ctl_id) \[ctl_id] = { \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -