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, "%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 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(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_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(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_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(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_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(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_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(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