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