struct kobj_type ktype;
struct class_device_attribute attr_v4l_minor_number;
struct class_device_attribute attr_unit_number;
+ int v4l_minor_number_created_ok;
+ int unit_number_created_ok;
};
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
struct class_device_attribute attr_debugcmd;
struct class_device_attribute attr_debuginfo;
+ int debugcmd_created_ok;
+ int debuginfo_created_ok;
};
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item {
struct class_device_attribute attr_name;
+ struct class_device_attribute attr_type;
struct class_device_attribute attr_min;
struct class_device_attribute attr_max;
struct class_device_attribute attr_enum;
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
- struct attribute *attr_gen[6];
+ struct attribute *attr_gen[7];
struct attribute_group grp;
+ int created_ok;
char name[80];
};
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
+static ssize_t show_type(int id,struct class_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->class_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 class_device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
#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) \
struct pvr2_sysfs_func_set {
ssize_t (*show_name)(struct class_device *,char *);
+ ssize_t (*show_type)(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 *);
#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, \
struct pvr2_sysfs_func_set *fp;
struct pvr2_ctrl *cptr;
unsigned int cnt,acnt;
+ int ret;
if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
return;
cip->cptr = cptr;
cip->chptr = sfp;
- cip->item_next = 0;
+ cip->item_next = NULL;
if (sfp->item_last) {
sfp->item_last->item_next = cip;
} else {
cip->attr_name.attr.mode = S_IRUGO;
cip->attr_name.show = fp->show_name;
+ cip->attr_type.attr.owner = THIS_MODULE;
+ cip->attr_type.attr.name = "type";
+ cip->attr_type.attr.mode = S_IRUGO;
+ cip->attr_type.show = fp->show_type;
+
cip->attr_min.attr.owner = THIS_MODULE;
cip->attr_min.attr.name = "min_val";
cip->attr_min.attr.mode = S_IRUGO;
acnt = 0;
cip->attr_gen[acnt++] = &cip->attr_name.attr;
+ cip->attr_gen[acnt++] = &cip->attr_type.attr;
cip->attr_gen[acnt++] = &cip->attr_val.attr;
cip->attr_val.show = fp->show_val_norm;
cip->attr_val.store = fp->store_val_norm;
cip->grp.name = cip->name;
cip->grp.attrs = cip->attr_gen;
- sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+ ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+ if (ret) {
+ printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
+ __FUNCTION__, ret);
+ return;
+ }
+ cip->created_ok = !0;
}
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
{
struct pvr2_sysfs_debugifc *dip;
+ int ret;
+
dip = kmalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
memset(dip,0,sizeof(*dip));
dip->attr_debuginfo.attr.mode = S_IRUGO;
dip->attr_debuginfo.show = debuginfo_show;
sfp->debugifc = dip;
- class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
- class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debugcmd_created_ok = !0;
+ }
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debuginfo_created_ok = !0;
+ }
}
static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
{
if (!sfp->debugifc) return;
- class_device_remove_file(sfp->class_dev,
- &sfp->debugifc->attr_debuginfo);
- class_device_remove_file(sfp->class_dev,&sfp->debugifc->attr_debugcmd);
+ if (sfp->debugifc->debuginfo_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debuginfo);
+ }
+ if (sfp->debugifc->debugcmd_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debugcmd);
+ }
kfree(sfp->debugifc);
- sfp->debugifc = 0;
+ sfp->debugifc = NULL;
}
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item *cip1,*cip2;
for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
cip2 = cip1->item_next;
- sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+ if (cip1->created_ok) {
+ sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+ }
pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
kfree(cip1);
}
pvr2_sysfs_tear_down_debugifc(sfp);
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
- class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
- class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number);
+ if (sfp->v4l_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ }
+ if (sfp->unit_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_unit_number);
+ }
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
- sfp->class_dev->class_data = 0;
+ sfp->class_dev->class_data = NULL;
class_device_unregister(sfp->class_dev);
- sfp->class_dev = 0;
+ sfp->class_dev = NULL;
}
{
struct usb_device *usb_dev;
struct class_device *class_dev;
+ int ret;
+
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
sfp->class_dev = class_dev;
class_dev->class_data = sfp;
- class_device_register(class_dev);
+ ret = class_device_register(class_dev);
+ if (ret) {
+ printk(KERN_ERR "%s: class_device_register failed\n",
+ __FUNCTION__);
+ kfree(class_dev);
+ return;
+ }
sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE;
sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
- sfp->attr_v4l_minor_number.store = 0;
- class_device_create_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
+ sfp->attr_v4l_minor_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_minor_number_created_ok = !0;
+ }
+
sfp->attr_unit_number.attr.owner = THIS_MODULE;
sfp->attr_unit_number.attr.name = "unit_number";
sfp->attr_unit_number.attr.mode = S_IRUGO;
sfp->attr_unit_number.show = unit_number_show;
- sfp->attr_unit_number.store = 0;
- class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ sfp->attr_unit_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->unit_number_created_ok = !0;
+ }
pvr2_sysfs_add_controls(sfp);
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_trace(
"Registration failed for pvr2_sysfs_class id=%p",clp);
kfree(clp);
- clp = 0;
+ clp = NULL;
}
return clp;
}