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