1// SPDX-License-Identifier: GPL-2.0-only
2/*
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_DEBUGIFC
13#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_DEBUGIFC
22 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_DEBUGIFC
41struct 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, fmt: "%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, fmt: "%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, fmt: "%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, fmt: "%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, valptr: &val);
140 if (ret < 0) return ret;
141 ret = pvr2_ctrl_value_to_sym(cip->cptr, mask: ~0, val,
142 buf, PAGE_SIZE - 1, len: &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, valptr: &val);
159 if (ret < 0) return ret;
160 ret = pvr2_ctrl_value_to_sym(cip->cptr, mask: ~0, val,
161 buf, PAGE_SIZE - 1, len: &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, valptr: &val);
178 if (ret < 0) return ret;
179 ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, mask: ~0, val,
180 buf, PAGE_SIZE - 1, len: &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, len: count,
243 maskptr: &mask, valptr: &val);
244 } else {
245 ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, len: count,
246 maskptr: &mask, valptr: &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, customfl: 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, customfl: 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(size: 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 enumeration
371 cip->attr_gen[acnt++] = &cip->attr_enum.attr;
372 break;
373 case pvr2_ctl_int:
374 // Control is an integer
375 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 bitmask
380 cip->attr_gen[acnt++] = &cip->attr_bits.attr;
381 break;
382 default: break;
383 }
384
385 cnt = scnprintf(buf: cip->name,size: sizeof(cip->name)-1,fmt: "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(kobj: &sfp->class_dev->kobj,grp: &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_DEBUGIFC
402static 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(size: 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(device: sfp->class_dev,entry: &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(device: sfp->class_dev,entry: &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(dev: sfp->class_dev,
450 attr: &sfp->debugifc->attr_debuginfo);
451 }
452 if (sfp->debugifc->debugcmd_created_ok) {
453 device_remove_file(dev: sfp->class_dev,
454 attr: &sfp->debugifc->attr_debugcmd);
455 }
456 kfree(objp: 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,ctl_id: 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(kobj: &sfp->class_dev->kobj,grp: &cip1->grp);
479 }
480 pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
481 kfree(objp: 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(objp: 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_DEBUGIFC
504 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(dev: sfp->class_dev,
509 attr: &sfp->attr_hdw_desc);
510 }
511 if (sfp->hdw_name_created_ok) {
512 device_remove_file(dev: sfp->class_dev,
513 attr: &sfp->attr_hdw_name);
514 }
515 if (sfp->bus_info_created_ok) {
516 device_remove_file(dev: sfp->class_dev,
517 attr: &sfp->attr_bus_info);
518 }
519 if (sfp->v4l_minor_number_created_ok) {
520 device_remove_file(dev: sfp->class_dev,
521 attr: &sfp->attr_v4l_minor_number);
522 }
523 if (sfp->v4l_radio_minor_number_created_ok) {
524 device_remove_file(dev: sfp->class_dev,
525 attr: &sfp->attr_v4l_radio_minor_number);
526 }
527 if (sfp->unit_number_created_ok) {
528 device_remove_file(dev: sfp->class_dev,
529 attr: &sfp->attr_unit_number);
530 }
531 pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
532 dev_set_drvdata(dev: sfp->class_dev, NULL);
533 dev = sfp->class_dev->parent;
534 sfp->class_dev->parent = NULL;
535 put_device(dev);
536 device_unregister(dev: 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(dev: class_dev);
546 if (!sfp) return -EINVAL;
547 return sysfs_emit(buf, fmt: "%d\n",
548 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
549 index: 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(dev: class_dev);
558 if (!sfp) return -EINVAL;
559 return sysfs_emit(buf, fmt: "%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(dev: class_dev);
569 if (!sfp) return -EINVAL;
570 return sysfs_emit(buf, fmt: "%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(dev: class_dev);
580 if (!sfp) return -EINVAL;
581 return sysfs_emit(buf, fmt: "%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(dev: class_dev);
592 if (!sfp) return -EINVAL;
593 return sysfs_emit(buf, fmt: "%d\n",
594 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
595 index: 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(dev: class_dev);
604 if (!sfp) return -EINVAL;
605 return sysfs_emit(buf, fmt: "%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(size: 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(dev: class_dev, name: "%s",
626 pvr2_hdw_get_device_identifier(sfp->channel.hdw));
627
628 class_dev->parent = get_device(dev: &usb_dev->dev);
629
630 sfp->class_dev = class_dev;
631 dev_set_drvdata(dev: class_dev, data: sfp);
632 ret = device_register(dev: class_dev);
633 if (ret) {
634 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
635 "device_register failed");
636 put_device(dev: 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(device: sfp->class_dev,
646 entry: &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(device: sfp->class_dev,
661 entry: &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(device: sfp->class_dev,entry: &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(device: sfp->class_dev,
690 entry: &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(device: sfp->class_dev,
705 entry: &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(device: sfp->class_dev,
720 entry: &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_DEBUGIFC
731 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(objp: sfp);
745}
746
747
748void pvr2_sysfs_create(struct pvr2_context *mp)
749{
750 struct pvr2_sysfs *sfp;
751 sfp = kzalloc(size: 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(class: &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(class: &pvr2_class);
772}
773
774
775#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
776static 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(dev: class_dev);
781 if (!sfp) return -EINVAL;
782 pvr2_hdw_trigger_module_log(hdw: sfp->channel.hdw);
783 return pvr2_debugifc_print_info(sfp->channel.hdw,buf_ptr: 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(dev: class_dev);
792 if (!sfp) return -EINVAL;
793 return pvr2_debugifc_print_status(sfp->channel.hdw,buf_ptr: 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(dev: class_dev);
805 if (!sfp) return -EINVAL;
806
807 ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf_ptr: buf,buf_size: count);
808 if (ret < 0) return ret;
809 return count;
810}
811#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
812

source code of linux/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c