812 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>5 */6 7#include <linux/string.h>8#include <linux/slab.h>9#include "pvrusb2-sysfs.h"10#include "pvrusb2-hdw.h"11#include "pvrusb2-debug.h"12#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC13#include "pvrusb2-debugifc.h"14#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */15 16#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)17 18struct pvr2_sysfs {19 struct pvr2_channel channel;20 struct device *class_dev;21#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC22 struct pvr2_sysfs_debugifc *debugifc;23#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */24 struct pvr2_sysfs_ctl_item *item_first;25 struct pvr2_sysfs_ctl_item *item_last;26 struct device_attribute attr_v4l_minor_number;27 struct device_attribute attr_v4l_radio_minor_number;28 struct device_attribute attr_unit_number;29 struct device_attribute attr_bus_info;30 struct device_attribute attr_hdw_name;31 struct device_attribute attr_hdw_desc;32 int v4l_minor_number_created_ok;33 int v4l_radio_minor_number_created_ok;34 int unit_number_created_ok;35 int bus_info_created_ok;36 int hdw_name_created_ok;37 int hdw_desc_created_ok;38};39 40#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC41struct pvr2_sysfs_debugifc {42 struct device_attribute attr_debugcmd;43 struct device_attribute attr_debuginfo;44 int debugcmd_created_ok;45 int debuginfo_created_ok;46};47#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */48 49struct pvr2_sysfs_ctl_item {50 struct device_attribute attr_name;51 struct device_attribute attr_type;52 struct device_attribute attr_min;53 struct device_attribute attr_max;54 struct device_attribute attr_def;55 struct device_attribute attr_enum;56 struct device_attribute attr_bits;57 struct device_attribute attr_val;58 struct device_attribute attr_custom;59 struct pvr2_ctrl *cptr;60 int ctl_id;61 struct pvr2_sysfs *chptr;62 struct pvr2_sysfs_ctl_item *item_next;63 struct attribute *attr_gen[8];64 struct attribute_group grp;65 int created_ok;66 char name[80];67};68 69static ssize_t show_name(struct device *class_dev,70 struct device_attribute *attr,71 char *buf)72{73 struct pvr2_sysfs_ctl_item *cip;74 const char *name;75 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name);76 name = pvr2_ctrl_get_desc(cip->cptr);77 pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",78 cip->chptr, cip->ctl_id, name);79 if (!name) return -EINVAL;80 return sysfs_emit(buf, "%s\n", name);81}82 83static ssize_t show_type(struct device *class_dev,84 struct device_attribute *attr,85 char *buf)86{87 struct pvr2_sysfs_ctl_item *cip;88 const char *name;89 enum pvr2_ctl_type tp;90 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type);91 tp = pvr2_ctrl_get_type(cip->cptr);92 switch (tp) {93 case pvr2_ctl_int: name = "integer"; break;94 case pvr2_ctl_enum: name = "enum"; break;95 case pvr2_ctl_bitmask: name = "bitmask"; break;96 case pvr2_ctl_bool: name = "boolean"; break;97 default: name = "?"; break;98 }99 pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",100 cip->chptr, cip->ctl_id, name);101 return sysfs_emit(buf, "%s\n", name);102}103 104static ssize_t show_min(struct device *class_dev,105 struct device_attribute *attr,106 char *buf)107{108 struct pvr2_sysfs_ctl_item *cip;109 long val;110 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min);111 val = pvr2_ctrl_get_min(cip->cptr);112 pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",113 cip->chptr, cip->ctl_id, val);114 return sysfs_emit(buf, "%ld\n", val);115}116 117static ssize_t show_max(struct device *class_dev,118 struct device_attribute *attr,119 char *buf)120{121 struct pvr2_sysfs_ctl_item *cip;122 long val;123 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max);124 val = pvr2_ctrl_get_max(cip->cptr);125 pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",126 cip->chptr, cip->ctl_id, val);127 return sysfs_emit(buf, "%ld\n", val);128}129 130static ssize_t show_def(struct device *class_dev,131 struct device_attribute *attr,132 char *buf)133{134 struct pvr2_sysfs_ctl_item *cip;135 int val;136 int ret;137 unsigned int cnt = 0;138 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def);139 ret = pvr2_ctrl_get_def(cip->cptr, &val);140 if (ret < 0) return ret;141 ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,142 buf, PAGE_SIZE - 1, &cnt);143 pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %.*s (%d)",144 cip->chptr, cip->ctl_id, cnt, buf, val);145 buf[cnt] = '\n';146 return cnt + 1;147}148 149static ssize_t show_val_norm(struct device *class_dev,150 struct device_attribute *attr,151 char *buf)152{153 struct pvr2_sysfs_ctl_item *cip;154 int val;155 int ret;156 unsigned int cnt = 0;157 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);158 ret = pvr2_ctrl_get_value(cip->cptr, &val);159 if (ret < 0) return ret;160 ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,161 buf, PAGE_SIZE - 1, &cnt);162 pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",163 cip->chptr, cip->ctl_id, cnt, buf, val);164 buf[cnt] = '\n';165 return cnt+1;166}167 168static ssize_t show_val_custom(struct device *class_dev,169 struct device_attribute *attr,170 char *buf)171{172 struct pvr2_sysfs_ctl_item *cip;173 int val;174 int ret;175 unsigned int cnt = 0;176 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);177 ret = pvr2_ctrl_get_value(cip->cptr, &val);178 if (ret < 0) return ret;179 ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val,180 buf, PAGE_SIZE - 1, &cnt);181 pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",182 cip->chptr, cip->ctl_id, cnt, buf, val);183 buf[cnt] = '\n';184 return cnt+1;185}186 187static ssize_t show_enum(struct device *class_dev,188 struct device_attribute *attr,189 char *buf)190{191 struct pvr2_sysfs_ctl_item *cip;192 long val;193 unsigned int bcnt, ccnt, ecnt;194 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum);195 ecnt = pvr2_ctrl_get_cnt(cip->cptr);196 bcnt = 0;197 for (val = 0; val < ecnt; val++) {198 pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt,199 PAGE_SIZE - bcnt, &ccnt);200 if (!ccnt) continue;201 bcnt += ccnt;202 if (bcnt >= PAGE_SIZE) break;203 buf[bcnt] = '\n';204 bcnt++;205 }206 pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",207 cip->chptr, cip->ctl_id);208 return bcnt;209}210 211static ssize_t show_bits(struct device *class_dev,212 struct device_attribute *attr,213 char *buf)214{215 struct pvr2_sysfs_ctl_item *cip;216 int valid_bits, msk;217 unsigned int bcnt, ccnt;218 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits);219 valid_bits = pvr2_ctrl_get_mask(cip->cptr);220 bcnt = 0;221 for (msk = 1; valid_bits; msk <<= 1) {222 if (!(msk & valid_bits)) continue;223 valid_bits &= ~msk;224 pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt,225 PAGE_SIZE - bcnt, &ccnt);226 bcnt += ccnt;227 if (bcnt >= PAGE_SIZE) break;228 buf[bcnt] = '\n';229 bcnt++;230 }231 pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",232 cip->chptr, cip->ctl_id);233 return bcnt;234}235 236static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl,237 const char *buf,unsigned int count)238{239 int ret;240 int mask,val;241 if (customfl) {242 ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count,243 &mask, &val);244 } else {245 ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count,246 &mask, &val);247 }248 if (ret < 0) return ret;249 ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val);250 pvr2_hdw_commit_ctl(cip->chptr->channel.hdw);251 return ret;252}253 254static ssize_t store_val_norm(struct device *class_dev,255 struct device_attribute *attr,256 const char *buf, size_t count)257{258 struct pvr2_sysfs_ctl_item *cip;259 int ret;260 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);261 pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",262 cip->chptr, cip->ctl_id, (int)count, buf);263 ret = store_val_any(cip, 0, buf, count);264 if (!ret) ret = count;265 return ret;266}267 268static ssize_t store_val_custom(struct device *class_dev,269 struct device_attribute *attr,270 const char *buf, size_t count)271{272 struct pvr2_sysfs_ctl_item *cip;273 int ret;274 cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);275 pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",276 cip->chptr, cip->ctl_id, (int)count, buf);277 ret = store_val_any(cip, 1, buf, count);278 if (!ret) ret = count;279 return ret;280}281 282static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)283{284 struct pvr2_sysfs_ctl_item *cip;285 struct pvr2_ctrl *cptr;286 unsigned int cnt,acnt;287 int ret;288 289 cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);290 if (!cptr) return;291 292 cip = kzalloc(sizeof(*cip),GFP_KERNEL);293 if (!cip) return;294 pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);295 296 cip->cptr = cptr;297 cip->ctl_id = ctl_id;298 299 cip->chptr = sfp;300 cip->item_next = NULL;301 if (sfp->item_last) {302 sfp->item_last->item_next = cip;303 } else {304 sfp->item_first = cip;305 }306 sfp->item_last = cip;307 308 sysfs_attr_init(&cip->attr_name.attr);309 cip->attr_name.attr.name = "name";310 cip->attr_name.attr.mode = S_IRUGO;311 cip->attr_name.show = show_name;312 313 sysfs_attr_init(&cip->attr_type.attr);314 cip->attr_type.attr.name = "type";315 cip->attr_type.attr.mode = S_IRUGO;316 cip->attr_type.show = show_type;317 318 sysfs_attr_init(&cip->attr_min.attr);319 cip->attr_min.attr.name = "min_val";320 cip->attr_min.attr.mode = S_IRUGO;321 cip->attr_min.show = show_min;322 323 sysfs_attr_init(&cip->attr_max.attr);324 cip->attr_max.attr.name = "max_val";325 cip->attr_max.attr.mode = S_IRUGO;326 cip->attr_max.show = show_max;327 328 sysfs_attr_init(&cip->attr_def.attr);329 cip->attr_def.attr.name = "def_val";330 cip->attr_def.attr.mode = S_IRUGO;331 cip->attr_def.show = show_def;332 333 sysfs_attr_init(&cip->attr_val.attr);334 cip->attr_val.attr.name = "cur_val";335 cip->attr_val.attr.mode = S_IRUGO;336 337 sysfs_attr_init(&cip->attr_custom.attr);338 cip->attr_custom.attr.name = "custom_val";339 cip->attr_custom.attr.mode = S_IRUGO;340 341 sysfs_attr_init(&cip->attr_enum.attr);342 cip->attr_enum.attr.name = "enum_val";343 cip->attr_enum.attr.mode = S_IRUGO;344 cip->attr_enum.show = show_enum;345 346 sysfs_attr_init(&cip->attr_bits.attr);347 cip->attr_bits.attr.name = "bit_val";348 cip->attr_bits.attr.mode = S_IRUGO;349 cip->attr_bits.show = show_bits;350 351 if (pvr2_ctrl_is_writable(cptr)) {352 cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;353 cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;354 }355 356 acnt = 0;357 cip->attr_gen[acnt++] = &cip->attr_name.attr;358 cip->attr_gen[acnt++] = &cip->attr_type.attr;359 cip->attr_gen[acnt++] = &cip->attr_val.attr;360 cip->attr_gen[acnt++] = &cip->attr_def.attr;361 cip->attr_val.show = show_val_norm;362 cip->attr_val.store = store_val_norm;363 if (pvr2_ctrl_has_custom_symbols(cptr)) {364 cip->attr_gen[acnt++] = &cip->attr_custom.attr;365 cip->attr_custom.show = show_val_custom;366 cip->attr_custom.store = store_val_custom;367 }368 switch (pvr2_ctrl_get_type(cptr)) {369 case pvr2_ctl_enum:370 // Control is an enumeration371 cip->attr_gen[acnt++] = &cip->attr_enum.attr;372 break;373 case pvr2_ctl_int:374 // Control is an integer375 cip->attr_gen[acnt++] = &cip->attr_min.attr;376 cip->attr_gen[acnt++] = &cip->attr_max.attr;377 break;378 case pvr2_ctl_bitmask:379 // Control is an bitmask380 cip->attr_gen[acnt++] = &cip->attr_bits.attr;381 break;382 default: break;383 }384 385 cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",386 pvr2_ctrl_get_name(cptr));387 cip->name[cnt] = 0;388 cip->grp.name = cip->name;389 cip->grp.attrs = cip->attr_gen;390 391 ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);392 if (ret) {393 pvr2_trace(PVR2_TRACE_ERROR_LEGS,394 "sysfs_create_group error: %d",395 ret);396 return;397 }398 cip->created_ok = !0;399}400 401#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC402static ssize_t debuginfo_show(struct device *, struct device_attribute *,403 char *);404static ssize_t debugcmd_show(struct device *, struct device_attribute *,405 char *);406static ssize_t debugcmd_store(struct device *, struct device_attribute *,407 const char *, size_t count);408 409static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)410{411 struct pvr2_sysfs_debugifc *dip;412 int ret;413 414 dip = kzalloc(sizeof(*dip),GFP_KERNEL);415 if (!dip) return;416 sysfs_attr_init(&dip->attr_debugcmd.attr);417 dip->attr_debugcmd.attr.name = "debugcmd";418 dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;419 dip->attr_debugcmd.show = debugcmd_show;420 dip->attr_debugcmd.store = debugcmd_store;421 sysfs_attr_init(&dip->attr_debuginfo.attr);422 dip->attr_debuginfo.attr.name = "debuginfo";423 dip->attr_debuginfo.attr.mode = S_IRUGO;424 dip->attr_debuginfo.show = debuginfo_show;425 sfp->debugifc = dip;426 ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);427 if (ret < 0) {428 pvr2_trace(PVR2_TRACE_ERROR_LEGS,429 "device_create_file error: %d",430 ret);431 } else {432 dip->debugcmd_created_ok = !0;433 }434 ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);435 if (ret < 0) {436 pvr2_trace(PVR2_TRACE_ERROR_LEGS,437 "device_create_file error: %d",438 ret);439 } else {440 dip->debuginfo_created_ok = !0;441 }442}443 444 445static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)446{447 if (!sfp->debugifc) return;448 if (sfp->debugifc->debuginfo_created_ok) {449 device_remove_file(sfp->class_dev,450 &sfp->debugifc->attr_debuginfo);451 }452 if (sfp->debugifc->debugcmd_created_ok) {453 device_remove_file(sfp->class_dev,454 &sfp->debugifc->attr_debugcmd);455 }456 kfree(sfp->debugifc);457 sfp->debugifc = NULL;458}459#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */460 461 462static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)463{464 unsigned int idx,cnt;465 cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);466 for (idx = 0; idx < cnt; idx++) {467 pvr2_sysfs_add_control(sfp,idx);468 }469}470 471 472static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)473{474 struct pvr2_sysfs_ctl_item *cip1,*cip2;475 for (cip1 = sfp->item_first; cip1; cip1 = cip2) {476 cip2 = cip1->item_next;477 if (cip1->created_ok) {478 sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);479 }480 pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);481 kfree(cip1);482 }483}484 485 486static void pvr2_sysfs_release(struct device *class_dev)487{488 pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);489 kfree(class_dev);490}491 492 493static struct class pvr2_class = {494 .name = "pvrusb2",495 .dev_release = pvr2_sysfs_release,496};497 498 499static void class_dev_destroy(struct pvr2_sysfs *sfp)500{501 struct device *dev;502 if (!sfp->class_dev) return;503#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC504 pvr2_sysfs_tear_down_debugifc(sfp);505#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */506 pvr2_sysfs_tear_down_controls(sfp);507 if (sfp->hdw_desc_created_ok) {508 device_remove_file(sfp->class_dev,509 &sfp->attr_hdw_desc);510 }511 if (sfp->hdw_name_created_ok) {512 device_remove_file(sfp->class_dev,513 &sfp->attr_hdw_name);514 }515 if (sfp->bus_info_created_ok) {516 device_remove_file(sfp->class_dev,517 &sfp->attr_bus_info);518 }519 if (sfp->v4l_minor_number_created_ok) {520 device_remove_file(sfp->class_dev,521 &sfp->attr_v4l_minor_number);522 }523 if (sfp->v4l_radio_minor_number_created_ok) {524 device_remove_file(sfp->class_dev,525 &sfp->attr_v4l_radio_minor_number);526 }527 if (sfp->unit_number_created_ok) {528 device_remove_file(sfp->class_dev,529 &sfp->attr_unit_number);530 }531 pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);532 dev_set_drvdata(sfp->class_dev, NULL);533 dev = sfp->class_dev->parent;534 sfp->class_dev->parent = NULL;535 put_device(dev);536 device_unregister(sfp->class_dev);537 sfp->class_dev = NULL;538}539 540 541static ssize_t v4l_minor_number_show(struct device *class_dev,542 struct device_attribute *attr, char *buf)543{544 struct pvr2_sysfs *sfp;545 sfp = dev_get_drvdata(class_dev);546 if (!sfp) return -EINVAL;547 return sysfs_emit(buf, "%d\n",548 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,549 pvr2_v4l_type_video));550}551 552 553static ssize_t bus_info_show(struct device *class_dev,554 struct device_attribute *attr, char *buf)555{556 struct pvr2_sysfs *sfp;557 sfp = dev_get_drvdata(class_dev);558 if (!sfp) return -EINVAL;559 return sysfs_emit(buf, "%s\n",560 pvr2_hdw_get_bus_info(sfp->channel.hdw));561}562 563 564static ssize_t hdw_name_show(struct device *class_dev,565 struct device_attribute *attr, char *buf)566{567 struct pvr2_sysfs *sfp;568 sfp = dev_get_drvdata(class_dev);569 if (!sfp) return -EINVAL;570 return sysfs_emit(buf, "%s\n",571 pvr2_hdw_get_type(sfp->channel.hdw));572}573 574 575static ssize_t hdw_desc_show(struct device *class_dev,576 struct device_attribute *attr, char *buf)577{578 struct pvr2_sysfs *sfp;579 sfp = dev_get_drvdata(class_dev);580 if (!sfp) return -EINVAL;581 return sysfs_emit(buf, "%s\n",582 pvr2_hdw_get_desc(sfp->channel.hdw));583}584 585 586static ssize_t v4l_radio_minor_number_show(struct device *class_dev,587 struct device_attribute *attr,588 char *buf)589{590 struct pvr2_sysfs *sfp;591 sfp = dev_get_drvdata(class_dev);592 if (!sfp) return -EINVAL;593 return sysfs_emit(buf, "%d\n",594 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,595 pvr2_v4l_type_radio));596}597 598 599static ssize_t unit_number_show(struct device *class_dev,600 struct device_attribute *attr, char *buf)601{602 struct pvr2_sysfs *sfp;603 sfp = dev_get_drvdata(class_dev);604 if (!sfp) return -EINVAL;605 return sysfs_emit(buf, "%d\n",606 pvr2_hdw_get_unit_number(sfp->channel.hdw));607}608 609 610static void class_dev_create(struct pvr2_sysfs *sfp)611{612 struct usb_device *usb_dev;613 struct device *class_dev;614 int ret;615 616 usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);617 if (!usb_dev) return;618 class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);619 if (!class_dev) return;620 621 pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);622 623 class_dev->class = &pvr2_class;624 625 dev_set_name(class_dev, "%s",626 pvr2_hdw_get_device_identifier(sfp->channel.hdw));627 628 class_dev->parent = get_device(&usb_dev->dev);629 630 sfp->class_dev = class_dev;631 dev_set_drvdata(class_dev, sfp);632 ret = device_register(class_dev);633 if (ret) {634 pvr2_trace(PVR2_TRACE_ERROR_LEGS,635 "device_register failed");636 put_device(class_dev);637 return;638 }639 640 sysfs_attr_init(&sfp->attr_v4l_minor_number.attr);641 sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";642 sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;643 sfp->attr_v4l_minor_number.show = v4l_minor_number_show;644 sfp->attr_v4l_minor_number.store = NULL;645 ret = device_create_file(sfp->class_dev,646 &sfp->attr_v4l_minor_number);647 if (ret < 0) {648 pvr2_trace(PVR2_TRACE_ERROR_LEGS,649 "device_create_file error: %d",650 ret);651 } else {652 sfp->v4l_minor_number_created_ok = !0;653 }654 655 sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr);656 sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";657 sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;658 sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;659 sfp->attr_v4l_radio_minor_number.store = NULL;660 ret = device_create_file(sfp->class_dev,661 &sfp->attr_v4l_radio_minor_number);662 if (ret < 0) {663 pvr2_trace(PVR2_TRACE_ERROR_LEGS,664 "device_create_file error: %d",665 ret);666 } else {667 sfp->v4l_radio_minor_number_created_ok = !0;668 }669 670 sysfs_attr_init(&sfp->attr_unit_number.attr);671 sfp->attr_unit_number.attr.name = "unit_number";672 sfp->attr_unit_number.attr.mode = S_IRUGO;673 sfp->attr_unit_number.show = unit_number_show;674 sfp->attr_unit_number.store = NULL;675 ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);676 if (ret < 0) {677 pvr2_trace(PVR2_TRACE_ERROR_LEGS,678 "device_create_file error: %d",679 ret);680 } else {681 sfp->unit_number_created_ok = !0;682 }683 684 sysfs_attr_init(&sfp->attr_bus_info.attr);685 sfp->attr_bus_info.attr.name = "bus_info_str";686 sfp->attr_bus_info.attr.mode = S_IRUGO;687 sfp->attr_bus_info.show = bus_info_show;688 sfp->attr_bus_info.store = NULL;689 ret = device_create_file(sfp->class_dev,690 &sfp->attr_bus_info);691 if (ret < 0) {692 pvr2_trace(PVR2_TRACE_ERROR_LEGS,693 "device_create_file error: %d",694 ret);695 } else {696 sfp->bus_info_created_ok = !0;697 }698 699 sysfs_attr_init(&sfp->attr_hdw_name.attr);700 sfp->attr_hdw_name.attr.name = "device_hardware_type";701 sfp->attr_hdw_name.attr.mode = S_IRUGO;702 sfp->attr_hdw_name.show = hdw_name_show;703 sfp->attr_hdw_name.store = NULL;704 ret = device_create_file(sfp->class_dev,705 &sfp->attr_hdw_name);706 if (ret < 0) {707 pvr2_trace(PVR2_TRACE_ERROR_LEGS,708 "device_create_file error: %d",709 ret);710 } else {711 sfp->hdw_name_created_ok = !0;712 }713 714 sysfs_attr_init(&sfp->attr_hdw_desc.attr);715 sfp->attr_hdw_desc.attr.name = "device_hardware_description";716 sfp->attr_hdw_desc.attr.mode = S_IRUGO;717 sfp->attr_hdw_desc.show = hdw_desc_show;718 sfp->attr_hdw_desc.store = NULL;719 ret = device_create_file(sfp->class_dev,720 &sfp->attr_hdw_desc);721 if (ret < 0) {722 pvr2_trace(PVR2_TRACE_ERROR_LEGS,723 "device_create_file error: %d",724 ret);725 } else {726 sfp->hdw_desc_created_ok = !0;727 }728 729 pvr2_sysfs_add_controls(sfp);730#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC731 pvr2_sysfs_add_debugifc(sfp);732#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */733}734 735 736static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)737{738 struct pvr2_sysfs *sfp;739 sfp = container_of(chp,struct pvr2_sysfs,channel);740 if (!sfp->channel.mc_head->disconnect_flag) return;741 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);742 class_dev_destroy(sfp);743 pvr2_channel_done(&sfp->channel);744 kfree(sfp);745}746 747 748void pvr2_sysfs_create(struct pvr2_context *mp)749{750 struct pvr2_sysfs *sfp;751 sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);752 if (!sfp)753 return;754 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);755 pvr2_channel_init(&sfp->channel,mp);756 sfp->channel.check_func = pvr2_sysfs_internal_check;757 758 class_dev_create(sfp);759}760 761 762void pvr2_sysfs_class_create(void)763{764 if (class_register(&pvr2_class))765 pvr2_sysfs_trace("Registration failed for pvr2_sysfs_class");766}767 768 769void pvr2_sysfs_class_destroy(void)770{771 class_unregister(&pvr2_class);772}773 774 775#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC776static ssize_t debuginfo_show(struct device *class_dev,777 struct device_attribute *attr, char *buf)778{779 struct pvr2_sysfs *sfp;780 sfp = dev_get_drvdata(class_dev);781 if (!sfp) return -EINVAL;782 pvr2_hdw_trigger_module_log(sfp->channel.hdw);783 return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);784}785 786 787static ssize_t debugcmd_show(struct device *class_dev,788 struct device_attribute *attr, char *buf)789{790 struct pvr2_sysfs *sfp;791 sfp = dev_get_drvdata(class_dev);792 if (!sfp) return -EINVAL;793 return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);794}795 796 797static ssize_t debugcmd_store(struct device *class_dev,798 struct device_attribute *attr,799 const char *buf, size_t count)800{801 struct pvr2_sysfs *sfp;802 int ret;803 804 sfp = dev_get_drvdata(class_dev);805 if (!sfp) return -EINVAL;806 807 ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);808 if (ret < 0) return ret;809 return count;810}811#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */812