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
69struct pvr2_sysfs_class {
70	struct class class;
71};
72
73static 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
87static 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
108static 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
121static 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
134static 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
153static 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
172static 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
191static 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
215static 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
240static 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
258static 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
272static 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
286static 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
406static ssize_t debuginfo_show(struct device *, struct device_attribute *,
407			      char *);
408static ssize_t debugcmd_show(struct device *, struct device_attribute *,
409			     char *);
410static ssize_t debugcmd_store(struct device *, struct device_attribute *,
411			      const char *, size_t count);
412
413static 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
449static 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
466static 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
476static 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
490static 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
499static 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
506static 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
548static 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
560static 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
571static 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
582static 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
593static 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
606static 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
617static 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
744static 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
756struct 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
772struct 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
792void 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
801static 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
812static 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
822static 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