12504ba9fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d855497eSMike Isely /*
3d855497eSMike Isely *
4d855497eSMike Isely * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5d855497eSMike Isely */
6d855497eSMike Isely
7d855497eSMike Isely #include <linux/string.h>
8d855497eSMike Isely #include <linux/slab.h>
9d855497eSMike Isely #include "pvrusb2-sysfs.h"
10d855497eSMike Isely #include "pvrusb2-hdw.h"
11d855497eSMike Isely #include "pvrusb2-debug.h"
12d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
13d855497eSMike Isely #include "pvrusb2-debugifc.h"
14d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
15d855497eSMike Isely
16d855497eSMike Isely #define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)
17d855497eSMike Isely
18d855497eSMike Isely struct pvr2_sysfs {
19d855497eSMike Isely struct pvr2_channel channel;
2054bd5b66SKay Sievers struct device *class_dev;
21d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
22d855497eSMike Isely struct pvr2_sysfs_debugifc *debugifc;
23d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
24d855497eSMike Isely struct pvr2_sysfs_ctl_item *item_first;
25d855497eSMike Isely struct pvr2_sysfs_ctl_item *item_last;
2654bd5b66SKay Sievers struct device_attribute attr_v4l_minor_number;
2754bd5b66SKay Sievers struct device_attribute attr_v4l_radio_minor_number;
2854bd5b66SKay Sievers struct device_attribute attr_unit_number;
2954bd5b66SKay Sievers struct device_attribute attr_bus_info;
3078a47101SMike Isely struct device_attribute attr_hdw_name;
3178a47101SMike Isely struct device_attribute attr_hdw_desc;
3208d41808SMike Isely int v4l_minor_number_created_ok;
332fdf3d9cSPantelis Koukousoulas int v4l_radio_minor_number_created_ok;
3408d41808SMike Isely int unit_number_created_ok;
3531a18547SMike Isely int bus_info_created_ok;
3678a47101SMike Isely int hdw_name_created_ok;
3778a47101SMike Isely int hdw_desc_created_ok;
38d855497eSMike Isely };
39d855497eSMike Isely
40d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
41d855497eSMike Isely struct pvr2_sysfs_debugifc {
4254bd5b66SKay Sievers struct device_attribute attr_debugcmd;
4354bd5b66SKay Sievers struct device_attribute attr_debuginfo;
4408d41808SMike Isely int debugcmd_created_ok;
4508d41808SMike Isely int debuginfo_created_ok;
46d855497eSMike Isely };
47d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
48d855497eSMike Isely
49d855497eSMike Isely struct pvr2_sysfs_ctl_item {
5054bd5b66SKay Sievers struct device_attribute attr_name;
5154bd5b66SKay Sievers struct device_attribute attr_type;
5254bd5b66SKay Sievers struct device_attribute attr_min;
5354bd5b66SKay Sievers struct device_attribute attr_max;
540b7c2c95SMike Isely struct device_attribute attr_def;
5554bd5b66SKay Sievers struct device_attribute attr_enum;
5654bd5b66SKay Sievers struct device_attribute attr_bits;
5754bd5b66SKay Sievers struct device_attribute attr_val;
5854bd5b66SKay Sievers struct device_attribute attr_custom;
59d855497eSMike Isely struct pvr2_ctrl *cptr;
60f90fe7a3SMike Isely int ctl_id;
61d855497eSMike Isely struct pvr2_sysfs *chptr;
62d855497eSMike Isely struct pvr2_sysfs_ctl_item *item_next;
637a6ac348SMike Isely struct attribute *attr_gen[8];
64d855497eSMike Isely struct attribute_group grp;
6508d41808SMike Isely int created_ok;
66d855497eSMike Isely char name[80];
67d855497eSMike Isely };
68d855497eSMike Isely
show_name(struct device * class_dev,struct device_attribute * attr,char * buf)69f90fe7a3SMike Isely static ssize_t show_name(struct device *class_dev,
70f90fe7a3SMike Isely struct device_attribute *attr,
71f90fe7a3SMike Isely char *buf)
72d855497eSMike Isely {
73f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
74d855497eSMike Isely const char *name;
75f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_name);
76f90fe7a3SMike Isely name = pvr2_ctrl_get_desc(cip->cptr);
77f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",
78f90fe7a3SMike Isely cip->chptr, cip->ctl_id, name);
79d855497eSMike Isely if (!name) return -EINVAL;
80*13e6756bSye xingchen return sysfs_emit(buf, "%s\n", name);
81d855497eSMike Isely }
82d855497eSMike Isely
show_type(struct device * class_dev,struct device_attribute * attr,char * buf)83f90fe7a3SMike Isely static ssize_t show_type(struct device *class_dev,
84f90fe7a3SMike Isely struct device_attribute *attr,
85f90fe7a3SMike Isely char *buf)
8633213963SMike Isely {
87f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
8833213963SMike Isely const char *name;
8933213963SMike Isely enum pvr2_ctl_type tp;
90f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_type);
91f90fe7a3SMike Isely tp = pvr2_ctrl_get_type(cip->cptr);
9233213963SMike Isely switch (tp) {
9333213963SMike Isely case pvr2_ctl_int: name = "integer"; break;
9433213963SMike Isely case pvr2_ctl_enum: name = "enum"; break;
9533213963SMike Isely case pvr2_ctl_bitmask: name = "bitmask"; break;
9633213963SMike Isely case pvr2_ctl_bool: name = "boolean"; break;
9733213963SMike Isely default: name = "?"; break;
9833213963SMike Isely }
99f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",
100f90fe7a3SMike Isely cip->chptr, cip->ctl_id, name);
101*13e6756bSye xingchen return sysfs_emit(buf, "%s\n", name);
10233213963SMike Isely }
10333213963SMike Isely
show_min(struct device * class_dev,struct device_attribute * attr,char * buf)104f90fe7a3SMike Isely static ssize_t show_min(struct device *class_dev,
105f90fe7a3SMike Isely struct device_attribute *attr,
106f90fe7a3SMike Isely char *buf)
107d855497eSMike Isely {
108f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
109d855497eSMike Isely long val;
110f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_min);
111f90fe7a3SMike Isely val = pvr2_ctrl_get_min(cip->cptr);
112f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",
113f90fe7a3SMike Isely cip->chptr, cip->ctl_id, val);
114*13e6756bSye xingchen return sysfs_emit(buf, "%ld\n", val);
115d855497eSMike Isely }
116d855497eSMike Isely
show_max(struct device * class_dev,struct device_attribute * attr,char * buf)117f90fe7a3SMike Isely static ssize_t show_max(struct device *class_dev,
118f90fe7a3SMike Isely struct device_attribute *attr,
119f90fe7a3SMike Isely char *buf)
120d855497eSMike Isely {
121f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
122d855497eSMike Isely long val;
123f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_max);
124f90fe7a3SMike Isely val = pvr2_ctrl_get_max(cip->cptr);
125f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",
126f90fe7a3SMike Isely cip->chptr, cip->ctl_id, val);
127*13e6756bSye xingchen return sysfs_emit(buf, "%ld\n", val);
128d855497eSMike Isely }
129d855497eSMike Isely
show_def(struct device * class_dev,struct device_attribute * attr,char * buf)1300b7c2c95SMike Isely static ssize_t show_def(struct device *class_dev,
1310b7c2c95SMike Isely struct device_attribute *attr,
1320b7c2c95SMike Isely char *buf)
1330b7c2c95SMike Isely {
1340b7c2c95SMike Isely struct pvr2_sysfs_ctl_item *cip;
1350b7c2c95SMike Isely int val;
1360b7c2c95SMike Isely int ret;
1377bf56f94SMike Isely unsigned int cnt = 0;
1380b7c2c95SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def);
1390b7c2c95SMike Isely ret = pvr2_ctrl_get_def(cip->cptr, &val);
1407bf56f94SMike Isely if (ret < 0) return ret;
1417bf56f94SMike Isely ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,
1427bf56f94SMike Isely buf, PAGE_SIZE - 1, &cnt);
1437bf56f94SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %.*s (%d)",
1447bf56f94SMike Isely cip->chptr, cip->ctl_id, cnt, buf, val);
1457bf56f94SMike Isely buf[cnt] = '\n';
1467bf56f94SMike Isely return cnt + 1;
1470b7c2c95SMike Isely }
1480b7c2c95SMike Isely
show_val_norm(struct device * class_dev,struct device_attribute * attr,char * buf)149f90fe7a3SMike Isely static ssize_t show_val_norm(struct device *class_dev,
150f90fe7a3SMike Isely struct device_attribute *attr,
151f90fe7a3SMike Isely char *buf)
152d855497eSMike Isely {
153f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
154f90fe7a3SMike Isely int val;
155f90fe7a3SMike Isely int ret;
156d855497eSMike Isely unsigned int cnt = 0;
157f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
158f90fe7a3SMike Isely ret = pvr2_ctrl_get_value(cip->cptr, &val);
159d855497eSMike Isely if (ret < 0) return ret;
160f90fe7a3SMike Isely ret = pvr2_ctrl_value_to_sym(cip->cptr, ~0, val,
161d855497eSMike Isely buf, PAGE_SIZE - 1, &cnt);
162d855497eSMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
163f90fe7a3SMike Isely cip->chptr, cip->ctl_id, cnt, buf, val);
164d855497eSMike Isely buf[cnt] = '\n';
165d855497eSMike Isely return cnt+1;
166d855497eSMike Isely }
167d855497eSMike Isely
show_val_custom(struct device * class_dev,struct device_attribute * attr,char * buf)168f90fe7a3SMike Isely static ssize_t show_val_custom(struct device *class_dev,
169f90fe7a3SMike Isely struct device_attribute *attr,
170f90fe7a3SMike Isely char *buf)
171d855497eSMike Isely {
172f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
173f90fe7a3SMike Isely int val;
174f90fe7a3SMike Isely int ret;
175d855497eSMike Isely unsigned int cnt = 0;
176f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
177f90fe7a3SMike Isely ret = pvr2_ctrl_get_value(cip->cptr, &val);
178d855497eSMike Isely if (ret < 0) return ret;
179f90fe7a3SMike Isely ret = pvr2_ctrl_custom_value_to_sym(cip->cptr, ~0, val,
180d855497eSMike Isely buf, PAGE_SIZE - 1, &cnt);
181d855497eSMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
182f90fe7a3SMike Isely cip->chptr, cip->ctl_id, cnt, buf, val);
183d855497eSMike Isely buf[cnt] = '\n';
184d855497eSMike Isely return cnt+1;
185d855497eSMike Isely }
186d855497eSMike Isely
show_enum(struct device * class_dev,struct device_attribute * attr,char * buf)187f90fe7a3SMike Isely static ssize_t show_enum(struct device *class_dev,
188f90fe7a3SMike Isely struct device_attribute *attr,
189f90fe7a3SMike Isely char *buf)
190d855497eSMike Isely {
191f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
192d855497eSMike Isely long val;
193d855497eSMike Isely unsigned int bcnt, ccnt, ecnt;
194f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_enum);
195f90fe7a3SMike Isely ecnt = pvr2_ctrl_get_cnt(cip->cptr);
196d855497eSMike Isely bcnt = 0;
197d855497eSMike Isely for (val = 0; val < ecnt; val++) {
198f90fe7a3SMike Isely pvr2_ctrl_get_valname(cip->cptr, val, buf + bcnt,
199f90fe7a3SMike Isely PAGE_SIZE - bcnt, &ccnt);
20045886771SMike Isely if (!ccnt) continue;
201d855497eSMike Isely bcnt += ccnt;
202d855497eSMike Isely if (bcnt >= PAGE_SIZE) break;
203d855497eSMike Isely buf[bcnt] = '\n';
204d855497eSMike Isely bcnt++;
205d855497eSMike Isely }
206f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",
207f90fe7a3SMike Isely cip->chptr, cip->ctl_id);
208d855497eSMike Isely return bcnt;
209d855497eSMike Isely }
210d855497eSMike Isely
show_bits(struct device * class_dev,struct device_attribute * attr,char * buf)211f90fe7a3SMike Isely static ssize_t show_bits(struct device *class_dev,
212f90fe7a3SMike Isely struct device_attribute *attr,
213f90fe7a3SMike Isely char *buf)
214d855497eSMike Isely {
215f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
216d855497eSMike Isely int valid_bits, msk;
217d855497eSMike Isely unsigned int bcnt, ccnt;
218f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_bits);
219f90fe7a3SMike Isely valid_bits = pvr2_ctrl_get_mask(cip->cptr);
220d855497eSMike Isely bcnt = 0;
221d855497eSMike Isely for (msk = 1; valid_bits; msk <<= 1) {
222d855497eSMike Isely if (!(msk & valid_bits)) continue;
223d855497eSMike Isely valid_bits &= ~msk;
224f90fe7a3SMike Isely pvr2_ctrl_get_valname(cip->cptr, msk, buf + bcnt,
225f90fe7a3SMike Isely PAGE_SIZE - bcnt, &ccnt);
226d855497eSMike Isely bcnt += ccnt;
227d855497eSMike Isely if (bcnt >= PAGE_SIZE) break;
228d855497eSMike Isely buf[bcnt] = '\n';
229d855497eSMike Isely bcnt++;
230d855497eSMike Isely }
231f90fe7a3SMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",
232f90fe7a3SMike Isely cip->chptr, cip->ctl_id);
233d855497eSMike Isely return bcnt;
234d855497eSMike Isely }
235d855497eSMike Isely
store_val_any(struct pvr2_sysfs_ctl_item * cip,int customfl,const char * buf,unsigned int count)236f90fe7a3SMike Isely static int store_val_any(struct pvr2_sysfs_ctl_item *cip, int customfl,
237d855497eSMike Isely const char *buf,unsigned int count)
238d855497eSMike Isely {
239d855497eSMike Isely int ret;
240d855497eSMike Isely int mask,val;
241d855497eSMike Isely if (customfl) {
242f90fe7a3SMike Isely ret = pvr2_ctrl_custom_sym_to_value(cip->cptr, buf, count,
243f90fe7a3SMike Isely &mask, &val);
244d855497eSMike Isely } else {
245f90fe7a3SMike Isely ret = pvr2_ctrl_sym_to_value(cip->cptr, buf, count,
246f90fe7a3SMike Isely &mask, &val);
247d855497eSMike Isely }
248d855497eSMike Isely if (ret < 0) return ret;
249f90fe7a3SMike Isely ret = pvr2_ctrl_set_mask_value(cip->cptr, mask, val);
250f90fe7a3SMike Isely pvr2_hdw_commit_ctl(cip->chptr->channel.hdw);
251d855497eSMike Isely return ret;
252d855497eSMike Isely }
253d855497eSMike Isely
store_val_norm(struct device * class_dev,struct device_attribute * attr,const char * buf,size_t count)254f90fe7a3SMike Isely static ssize_t store_val_norm(struct device *class_dev,
255f90fe7a3SMike Isely struct device_attribute *attr,
256d855497eSMike Isely const char *buf, size_t count)
257d855497eSMike Isely {
258f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
259d855497eSMike Isely int ret;
260f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_val);
261bedbbf8bSMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",
262f90fe7a3SMike Isely cip->chptr, cip->ctl_id, (int)count, buf);
263f90fe7a3SMike Isely ret = store_val_any(cip, 0, buf, count);
264d855497eSMike Isely if (!ret) ret = count;
265d855497eSMike Isely return ret;
266d855497eSMike Isely }
267d855497eSMike Isely
store_val_custom(struct device * class_dev,struct device_attribute * attr,const char * buf,size_t count)268f90fe7a3SMike Isely static ssize_t store_val_custom(struct device *class_dev,
269f90fe7a3SMike Isely struct device_attribute *attr,
270d855497eSMike Isely const char *buf, size_t count)
271d855497eSMike Isely {
272f90fe7a3SMike Isely struct pvr2_sysfs_ctl_item *cip;
273d855497eSMike Isely int ret;
274f90fe7a3SMike Isely cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_custom);
275bedbbf8bSMike Isely pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",
276f90fe7a3SMike Isely cip->chptr, cip->ctl_id, (int)count, buf);
277f90fe7a3SMike Isely ret = store_val_any(cip, 1, buf, count);
278d855497eSMike Isely if (!ret) ret = count;
279d855497eSMike Isely return ret;
280d855497eSMike Isely }
281d855497eSMike Isely
pvr2_sysfs_add_control(struct pvr2_sysfs * sfp,int ctl_id)282d855497eSMike Isely static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
283d855497eSMike Isely {
284d855497eSMike Isely struct pvr2_sysfs_ctl_item *cip;
285d855497eSMike Isely struct pvr2_ctrl *cptr;
286d855497eSMike Isely unsigned int cnt,acnt;
28708d41808SMike Isely int ret;
288d855497eSMike Isely
289d855497eSMike Isely cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
290d855497eSMike Isely if (!cptr) return;
291d855497eSMike Isely
292ca545f7cSMike Isely cip = kzalloc(sizeof(*cip),GFP_KERNEL);
293d855497eSMike Isely if (!cip) return;
294d855497eSMike Isely pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
295d855497eSMike Isely
296d855497eSMike Isely cip->cptr = cptr;
297f90fe7a3SMike Isely cip->ctl_id = ctl_id;
298d855497eSMike Isely
299d855497eSMike Isely cip->chptr = sfp;
300a0fd1cb1SMike Isely cip->item_next = NULL;
301d855497eSMike Isely if (sfp->item_last) {
302d855497eSMike Isely sfp->item_last->item_next = cip;
303d855497eSMike Isely } else {
304d855497eSMike Isely sfp->item_first = cip;
305d855497eSMike Isely }
306d855497eSMike Isely sfp->item_last = cip;
307d855497eSMike Isely
30819a0a296SMike Isely sysfs_attr_init(&cip->attr_name.attr);
309d855497eSMike Isely cip->attr_name.attr.name = "name";
310d855497eSMike Isely cip->attr_name.attr.mode = S_IRUGO;
311f90fe7a3SMike Isely cip->attr_name.show = show_name;
312d855497eSMike Isely
31319a0a296SMike Isely sysfs_attr_init(&cip->attr_type.attr);
31433213963SMike Isely cip->attr_type.attr.name = "type";
31533213963SMike Isely cip->attr_type.attr.mode = S_IRUGO;
316f90fe7a3SMike Isely cip->attr_type.show = show_type;
31733213963SMike Isely
31819a0a296SMike Isely sysfs_attr_init(&cip->attr_min.attr);
319d855497eSMike Isely cip->attr_min.attr.name = "min_val";
320d855497eSMike Isely cip->attr_min.attr.mode = S_IRUGO;
321f90fe7a3SMike Isely cip->attr_min.show = show_min;
322d855497eSMike Isely
32319a0a296SMike Isely sysfs_attr_init(&cip->attr_max.attr);
324d855497eSMike Isely cip->attr_max.attr.name = "max_val";
325d855497eSMike Isely cip->attr_max.attr.mode = S_IRUGO;
326f90fe7a3SMike Isely cip->attr_max.show = show_max;
327d855497eSMike Isely
32819a0a296SMike Isely sysfs_attr_init(&cip->attr_def.attr);
3290b7c2c95SMike Isely cip->attr_def.attr.name = "def_val";
3300b7c2c95SMike Isely cip->attr_def.attr.mode = S_IRUGO;
3310b7c2c95SMike Isely cip->attr_def.show = show_def;
3320b7c2c95SMike Isely
33319a0a296SMike Isely sysfs_attr_init(&cip->attr_val.attr);
334d855497eSMike Isely cip->attr_val.attr.name = "cur_val";
335d855497eSMike Isely cip->attr_val.attr.mode = S_IRUGO;
336d855497eSMike Isely
33719a0a296SMike Isely sysfs_attr_init(&cip->attr_custom.attr);
338d855497eSMike Isely cip->attr_custom.attr.name = "custom_val";
339d855497eSMike Isely cip->attr_custom.attr.mode = S_IRUGO;
340d855497eSMike Isely
34119a0a296SMike Isely sysfs_attr_init(&cip->attr_enum.attr);
342d855497eSMike Isely cip->attr_enum.attr.name = "enum_val";
343d855497eSMike Isely cip->attr_enum.attr.mode = S_IRUGO;
344f90fe7a3SMike Isely cip->attr_enum.show = show_enum;
345d855497eSMike Isely
34619a0a296SMike Isely sysfs_attr_init(&cip->attr_bits.attr);
347d855497eSMike Isely cip->attr_bits.attr.name = "bit_val";
348d855497eSMike Isely cip->attr_bits.attr.mode = S_IRUGO;
349f90fe7a3SMike Isely cip->attr_bits.show = show_bits;
350d855497eSMike Isely
351d855497eSMike Isely if (pvr2_ctrl_is_writable(cptr)) {
352d855497eSMike Isely cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
353d855497eSMike Isely cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
354d855497eSMike Isely }
355d855497eSMike Isely
356d855497eSMike Isely acnt = 0;
357d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_name.attr;
35833213963SMike Isely cip->attr_gen[acnt++] = &cip->attr_type.attr;
359d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_val.attr;
3600b7c2c95SMike Isely cip->attr_gen[acnt++] = &cip->attr_def.attr;
361f90fe7a3SMike Isely cip->attr_val.show = show_val_norm;
362f90fe7a3SMike Isely cip->attr_val.store = store_val_norm;
363d855497eSMike Isely if (pvr2_ctrl_has_custom_symbols(cptr)) {
364d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_custom.attr;
365f90fe7a3SMike Isely cip->attr_custom.show = show_val_custom;
366f90fe7a3SMike Isely cip->attr_custom.store = store_val_custom;
367d855497eSMike Isely }
368d855497eSMike Isely switch (pvr2_ctrl_get_type(cptr)) {
369d855497eSMike Isely case pvr2_ctl_enum:
370d855497eSMike Isely // Control is an enumeration
371d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_enum.attr;
372d855497eSMike Isely break;
373d855497eSMike Isely case pvr2_ctl_int:
374d855497eSMike Isely // Control is an integer
375d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_min.attr;
376d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_max.attr;
377d855497eSMike Isely break;
378d855497eSMike Isely case pvr2_ctl_bitmask:
379d855497eSMike Isely // Control is an bitmask
380d855497eSMike Isely cip->attr_gen[acnt++] = &cip->attr_bits.attr;
381d855497eSMike Isely break;
382d855497eSMike Isely default: break;
383d855497eSMike Isely }
384d855497eSMike Isely
385d855497eSMike Isely cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
386d855497eSMike Isely pvr2_ctrl_get_name(cptr));
387d855497eSMike Isely cip->name[cnt] = 0;
388d855497eSMike Isely cip->grp.name = cip->name;
389d855497eSMike Isely cip->grp.attrs = cip->attr_gen;
390d855497eSMike Isely
39108d41808SMike Isely ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
39208d41808SMike Isely if (ret) {
39349844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
39449844c29SMike Isely "sysfs_create_group error: %d",
39549844c29SMike Isely ret);
39608d41808SMike Isely return;
39708d41808SMike Isely }
39808d41808SMike Isely cip->created_ok = !0;
399d855497eSMike Isely }
400d855497eSMike Isely
401d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
402c726b65dSTrent Piepho static ssize_t debuginfo_show(struct device *, struct device_attribute *,
403c726b65dSTrent Piepho char *);
404c726b65dSTrent Piepho static ssize_t debugcmd_show(struct device *, struct device_attribute *,
405c726b65dSTrent Piepho char *);
406c726b65dSTrent Piepho static ssize_t debugcmd_store(struct device *, struct device_attribute *,
407c726b65dSTrent Piepho const char *, size_t count);
408d855497eSMike Isely
pvr2_sysfs_add_debugifc(struct pvr2_sysfs * sfp)409d855497eSMike Isely static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
410d855497eSMike Isely {
411d855497eSMike Isely struct pvr2_sysfs_debugifc *dip;
4123117beecSMichael Krufky int ret;
4133117beecSMichael Krufky
414ca545f7cSMike Isely dip = kzalloc(sizeof(*dip),GFP_KERNEL);
415d855497eSMike Isely if (!dip) return;
41612765517SWolfram Sang sysfs_attr_init(&dip->attr_debugcmd.attr);
417d855497eSMike Isely dip->attr_debugcmd.attr.name = "debugcmd";
418d855497eSMike Isely dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
419d855497eSMike Isely dip->attr_debugcmd.show = debugcmd_show;
420d855497eSMike Isely dip->attr_debugcmd.store = debugcmd_store;
42112765517SWolfram Sang sysfs_attr_init(&dip->attr_debuginfo.attr);
422d855497eSMike Isely dip->attr_debuginfo.attr.name = "debuginfo";
423d855497eSMike Isely dip->attr_debuginfo.attr.mode = S_IRUGO;
424d855497eSMike Isely dip->attr_debuginfo.show = debuginfo_show;
425d855497eSMike Isely sfp->debugifc = dip;
42654bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
42708d41808SMike Isely if (ret < 0) {
42849844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
42949844c29SMike Isely "device_create_file error: %d",
43049844c29SMike Isely ret);
43108d41808SMike Isely } else {
43208d41808SMike Isely dip->debugcmd_created_ok = !0;
43308d41808SMike Isely }
43454bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
43508d41808SMike Isely if (ret < 0) {
43649844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
43749844c29SMike Isely "device_create_file error: %d",
43849844c29SMike Isely ret);
43908d41808SMike Isely } else {
44008d41808SMike Isely dip->debuginfo_created_ok = !0;
44108d41808SMike Isely }
442d855497eSMike Isely }
443d855497eSMike Isely
444d855497eSMike Isely
pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs * sfp)445d855497eSMike Isely static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
446d855497eSMike Isely {
447d855497eSMike Isely if (!sfp->debugifc) return;
44808d41808SMike Isely if (sfp->debugifc->debuginfo_created_ok) {
44954bd5b66SKay Sievers device_remove_file(sfp->class_dev,
450d855497eSMike Isely &sfp->debugifc->attr_debuginfo);
45108d41808SMike Isely }
45208d41808SMike Isely if (sfp->debugifc->debugcmd_created_ok) {
45354bd5b66SKay Sievers device_remove_file(sfp->class_dev,
45408d41808SMike Isely &sfp->debugifc->attr_debugcmd);
45508d41808SMike Isely }
456d855497eSMike Isely kfree(sfp->debugifc);
457a0fd1cb1SMike Isely sfp->debugifc = NULL;
458d855497eSMike Isely }
459d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
460d855497eSMike Isely
461d855497eSMike Isely
pvr2_sysfs_add_controls(struct pvr2_sysfs * sfp)462d855497eSMike Isely static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
463d855497eSMike Isely {
464d855497eSMike Isely unsigned int idx,cnt;
465d855497eSMike Isely cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
466d855497eSMike Isely for (idx = 0; idx < cnt; idx++) {
467d855497eSMike Isely pvr2_sysfs_add_control(sfp,idx);
468d855497eSMike Isely }
469d855497eSMike Isely }
470d855497eSMike Isely
471d855497eSMike Isely
pvr2_sysfs_tear_down_controls(struct pvr2_sysfs * sfp)472d855497eSMike Isely static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
473d855497eSMike Isely {
474d855497eSMike Isely struct pvr2_sysfs_ctl_item *cip1,*cip2;
475d855497eSMike Isely for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
476d855497eSMike Isely cip2 = cip1->item_next;
47708d41808SMike Isely if (cip1->created_ok) {
478d855497eSMike Isely sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
47908d41808SMike Isely }
480d855497eSMike Isely pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
481d855497eSMike Isely kfree(cip1);
482d855497eSMike Isely }
483d855497eSMike Isely }
484d855497eSMike Isely
485d855497eSMike Isely
pvr2_sysfs_release(struct device * class_dev)48654bd5b66SKay Sievers static void pvr2_sysfs_release(struct device *class_dev)
487d855497eSMike Isely {
488d855497eSMike Isely pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
489d855497eSMike Isely kfree(class_dev);
490d855497eSMike Isely }
491d855497eSMike Isely
492d855497eSMike Isely
4936332a6ceSGreg Kroah-Hartman static struct class pvr2_class = {
4946332a6ceSGreg Kroah-Hartman .name = "pvrusb2",
4956332a6ceSGreg Kroah-Hartman .dev_release = pvr2_sysfs_release,
4966332a6ceSGreg Kroah-Hartman };
4976332a6ceSGreg Kroah-Hartman
4986332a6ceSGreg Kroah-Hartman
class_dev_destroy(struct pvr2_sysfs * sfp)499d855497eSMike Isely static void class_dev_destroy(struct pvr2_sysfs *sfp)
500d855497eSMike Isely {
50128c4a5e6SMike Isely struct device *dev;
502d855497eSMike Isely if (!sfp->class_dev) return;
503d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
504d855497eSMike Isely pvr2_sysfs_tear_down_debugifc(sfp);
505d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
506d855497eSMike Isely pvr2_sysfs_tear_down_controls(sfp);
50778a47101SMike Isely if (sfp->hdw_desc_created_ok) {
50878a47101SMike Isely device_remove_file(sfp->class_dev,
50978a47101SMike Isely &sfp->attr_hdw_desc);
51078a47101SMike Isely }
51178a47101SMike Isely if (sfp->hdw_name_created_ok) {
51278a47101SMike Isely device_remove_file(sfp->class_dev,
51378a47101SMike Isely &sfp->attr_hdw_name);
51478a47101SMike Isely }
51531a18547SMike Isely if (sfp->bus_info_created_ok) {
51654bd5b66SKay Sievers device_remove_file(sfp->class_dev,
51731a18547SMike Isely &sfp->attr_bus_info);
51831a18547SMike Isely }
51908d41808SMike Isely if (sfp->v4l_minor_number_created_ok) {
52054bd5b66SKay Sievers device_remove_file(sfp->class_dev,
52108d41808SMike Isely &sfp->attr_v4l_minor_number);
52208d41808SMike Isely }
5232fdf3d9cSPantelis Koukousoulas if (sfp->v4l_radio_minor_number_created_ok) {
52454bd5b66SKay Sievers device_remove_file(sfp->class_dev,
5252fdf3d9cSPantelis Koukousoulas &sfp->attr_v4l_radio_minor_number);
5262fdf3d9cSPantelis Koukousoulas }
52708d41808SMike Isely if (sfp->unit_number_created_ok) {
52854bd5b66SKay Sievers device_remove_file(sfp->class_dev,
52908d41808SMike Isely &sfp->attr_unit_number);
53008d41808SMike Isely }
531d855497eSMike Isely pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
53279510cdbSGreg Kroah-Hartman dev_set_drvdata(sfp->class_dev, NULL);
53328c4a5e6SMike Isely dev = sfp->class_dev->parent;
53428c4a5e6SMike Isely sfp->class_dev->parent = NULL;
53528c4a5e6SMike Isely put_device(dev);
53654bd5b66SKay Sievers device_unregister(sfp->class_dev);
537a0fd1cb1SMike Isely sfp->class_dev = NULL;
538d855497eSMike Isely }
539d855497eSMike Isely
540d855497eSMike Isely
v4l_minor_number_show(struct device * class_dev,struct device_attribute * attr,char * buf)54154bd5b66SKay Sievers static ssize_t v4l_minor_number_show(struct device *class_dev,
54254bd5b66SKay Sievers struct device_attribute *attr, char *buf)
543d855497eSMike Isely {
544d855497eSMike Isely struct pvr2_sysfs *sfp;
54579510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
546d855497eSMike Isely if (!sfp) return -EINVAL;
547*13e6756bSye xingchen return sysfs_emit(buf, "%d\n",
548fd5a75feSMike Isely pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
5498079384eSMike Isely pvr2_v4l_type_video));
5502fdf3d9cSPantelis Koukousoulas }
5512fdf3d9cSPantelis Koukousoulas
5522fdf3d9cSPantelis Koukousoulas
bus_info_show(struct device * class_dev,struct device_attribute * attr,char * buf)55354bd5b66SKay Sievers static ssize_t bus_info_show(struct device *class_dev,
55454bd5b66SKay Sievers struct device_attribute *attr, char *buf)
55531a18547SMike Isely {
55631a18547SMike Isely struct pvr2_sysfs *sfp;
55779510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
55831a18547SMike Isely if (!sfp) return -EINVAL;
559*13e6756bSye xingchen return sysfs_emit(buf, "%s\n",
56031a18547SMike Isely pvr2_hdw_get_bus_info(sfp->channel.hdw));
56131a18547SMike Isely }
56231a18547SMike Isely
56331a18547SMike Isely
hdw_name_show(struct device * class_dev,struct device_attribute * attr,char * buf)56478a47101SMike Isely static ssize_t hdw_name_show(struct device *class_dev,
56578a47101SMike Isely struct device_attribute *attr, char *buf)
56678a47101SMike Isely {
56778a47101SMike Isely struct pvr2_sysfs *sfp;
56879510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
56978a47101SMike Isely if (!sfp) return -EINVAL;
570*13e6756bSye xingchen return sysfs_emit(buf, "%s\n",
57178a47101SMike Isely pvr2_hdw_get_type(sfp->channel.hdw));
57278a47101SMike Isely }
57378a47101SMike Isely
57478a47101SMike Isely
hdw_desc_show(struct device * class_dev,struct device_attribute * attr,char * buf)57578a47101SMike Isely static ssize_t hdw_desc_show(struct device *class_dev,
57678a47101SMike Isely struct device_attribute *attr, char *buf)
57778a47101SMike Isely {
57878a47101SMike Isely struct pvr2_sysfs *sfp;
57979510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
58078a47101SMike Isely if (!sfp) return -EINVAL;
581*13e6756bSye xingchen return sysfs_emit(buf, "%s\n",
58278a47101SMike Isely pvr2_hdw_get_desc(sfp->channel.hdw));
58378a47101SMike Isely }
58478a47101SMike Isely
58578a47101SMike Isely
v4l_radio_minor_number_show(struct device * class_dev,struct device_attribute * attr,char * buf)58654bd5b66SKay Sievers static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
58754bd5b66SKay Sievers struct device_attribute *attr,
5882fdf3d9cSPantelis Koukousoulas char *buf)
5892fdf3d9cSPantelis Koukousoulas {
5902fdf3d9cSPantelis Koukousoulas struct pvr2_sysfs *sfp;
59179510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
5922fdf3d9cSPantelis Koukousoulas if (!sfp) return -EINVAL;
593*13e6756bSye xingchen return sysfs_emit(buf, "%d\n",
594fd5a75feSMike Isely pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
5958079384eSMike Isely pvr2_v4l_type_radio));
596d855497eSMike Isely }
597d855497eSMike Isely
598d855497eSMike Isely
unit_number_show(struct device * class_dev,struct device_attribute * attr,char * buf)59954bd5b66SKay Sievers static ssize_t unit_number_show(struct device *class_dev,
60054bd5b66SKay Sievers struct device_attribute *attr, char *buf)
601d855497eSMike Isely {
602d855497eSMike Isely struct pvr2_sysfs *sfp;
60379510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
604d855497eSMike Isely if (!sfp) return -EINVAL;
605*13e6756bSye xingchen return sysfs_emit(buf, "%d\n",
606d855497eSMike Isely pvr2_hdw_get_unit_number(sfp->channel.hdw));
607d855497eSMike Isely }
608d855497eSMike Isely
609d855497eSMike Isely
class_dev_create(struct pvr2_sysfs * sfp)6106332a6ceSGreg Kroah-Hartman static void class_dev_create(struct pvr2_sysfs *sfp)
611d855497eSMike Isely {
612d855497eSMike Isely struct usb_device *usb_dev;
61354bd5b66SKay Sievers struct device *class_dev;
6143117beecSMichael Krufky int ret;
6153117beecSMichael Krufky
616d855497eSMike Isely usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
617d855497eSMike Isely if (!usb_dev) return;
618ca545f7cSMike Isely class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
619d855497eSMike Isely if (!class_dev) return;
620d855497eSMike Isely
621d855497eSMike Isely pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
622d855497eSMike Isely
6236332a6ceSGreg Kroah-Hartman class_dev->class = &pvr2_class;
62428c4a5e6SMike Isely
625730e92c9SMike Isely dev_set_name(class_dev, "%s",
626730e92c9SMike Isely pvr2_hdw_get_device_identifier(sfp->channel.hdw));
627d855497eSMike Isely
62828c4a5e6SMike Isely class_dev->parent = get_device(&usb_dev->dev);
629d855497eSMike Isely
630d855497eSMike Isely sfp->class_dev = class_dev;
63179510cdbSGreg Kroah-Hartman dev_set_drvdata(class_dev, sfp);
63254bd5b66SKay Sievers ret = device_register(class_dev);
6333117beecSMichael Krufky if (ret) {
63449844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
63549844c29SMike Isely "device_register failed");
636a519d70eSVasiliy Kulikov put_device(class_dev);
6373117beecSMichael Krufky return;
6383117beecSMichael Krufky }
639d855497eSMike Isely
64012765517SWolfram Sang sysfs_attr_init(&sfp->attr_v4l_minor_number.attr);
641d855497eSMike Isely sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
642d855497eSMike Isely sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
643d855497eSMike Isely sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
644a0fd1cb1SMike Isely sfp->attr_v4l_minor_number.store = NULL;
64554bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,
64608d41808SMike Isely &sfp->attr_v4l_minor_number);
64708d41808SMike Isely if (ret < 0) {
64849844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
64949844c29SMike Isely "device_create_file error: %d",
65049844c29SMike Isely ret);
65108d41808SMike Isely } else {
65208d41808SMike Isely sfp->v4l_minor_number_created_ok = !0;
65308d41808SMike Isely }
6543117beecSMichael Krufky
65512765517SWolfram Sang sysfs_attr_init(&sfp->attr_v4l_radio_minor_number.attr);
6562fdf3d9cSPantelis Koukousoulas sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
6572fdf3d9cSPantelis Koukousoulas sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
6582fdf3d9cSPantelis Koukousoulas sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
6592fdf3d9cSPantelis Koukousoulas sfp->attr_v4l_radio_minor_number.store = NULL;
66054bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,
6612fdf3d9cSPantelis Koukousoulas &sfp->attr_v4l_radio_minor_number);
6622fdf3d9cSPantelis Koukousoulas if (ret < 0) {
66349844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
66449844c29SMike Isely "device_create_file error: %d",
66549844c29SMike Isely ret);
6662fdf3d9cSPantelis Koukousoulas } else {
6672fdf3d9cSPantelis Koukousoulas sfp->v4l_radio_minor_number_created_ok = !0;
6682fdf3d9cSPantelis Koukousoulas }
6692fdf3d9cSPantelis Koukousoulas
67012765517SWolfram Sang sysfs_attr_init(&sfp->attr_unit_number.attr);
671d855497eSMike Isely sfp->attr_unit_number.attr.name = "unit_number";
672d855497eSMike Isely sfp->attr_unit_number.attr.mode = S_IRUGO;
673d855497eSMike Isely sfp->attr_unit_number.show = unit_number_show;
674a0fd1cb1SMike Isely sfp->attr_unit_number.store = NULL;
67554bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
67608d41808SMike Isely if (ret < 0) {
67749844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
67849844c29SMike Isely "device_create_file error: %d",
67949844c29SMike Isely ret);
68008d41808SMike Isely } else {
68108d41808SMike Isely sfp->unit_number_created_ok = !0;
68208d41808SMike Isely }
683d855497eSMike Isely
68412765517SWolfram Sang sysfs_attr_init(&sfp->attr_bus_info.attr);
68531a18547SMike Isely sfp->attr_bus_info.attr.name = "bus_info_str";
68631a18547SMike Isely sfp->attr_bus_info.attr.mode = S_IRUGO;
68731a18547SMike Isely sfp->attr_bus_info.show = bus_info_show;
68831a18547SMike Isely sfp->attr_bus_info.store = NULL;
68954bd5b66SKay Sievers ret = device_create_file(sfp->class_dev,
69031a18547SMike Isely &sfp->attr_bus_info);
69131a18547SMike Isely if (ret < 0) {
69249844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
69349844c29SMike Isely "device_create_file error: %d",
69449844c29SMike Isely ret);
69531a18547SMike Isely } else {
69631a18547SMike Isely sfp->bus_info_created_ok = !0;
69731a18547SMike Isely }
69831a18547SMike Isely
69912765517SWolfram Sang sysfs_attr_init(&sfp->attr_hdw_name.attr);
70078a47101SMike Isely sfp->attr_hdw_name.attr.name = "device_hardware_type";
70178a47101SMike Isely sfp->attr_hdw_name.attr.mode = S_IRUGO;
70278a47101SMike Isely sfp->attr_hdw_name.show = hdw_name_show;
70378a47101SMike Isely sfp->attr_hdw_name.store = NULL;
70478a47101SMike Isely ret = device_create_file(sfp->class_dev,
70578a47101SMike Isely &sfp->attr_hdw_name);
70678a47101SMike Isely if (ret < 0) {
70749844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
70849844c29SMike Isely "device_create_file error: %d",
70949844c29SMike Isely ret);
71078a47101SMike Isely } else {
71178a47101SMike Isely sfp->hdw_name_created_ok = !0;
71278a47101SMike Isely }
71378a47101SMike Isely
71412765517SWolfram Sang sysfs_attr_init(&sfp->attr_hdw_desc.attr);
71578a47101SMike Isely sfp->attr_hdw_desc.attr.name = "device_hardware_description";
71678a47101SMike Isely sfp->attr_hdw_desc.attr.mode = S_IRUGO;
71778a47101SMike Isely sfp->attr_hdw_desc.show = hdw_desc_show;
71878a47101SMike Isely sfp->attr_hdw_desc.store = NULL;
71978a47101SMike Isely ret = device_create_file(sfp->class_dev,
72078a47101SMike Isely &sfp->attr_hdw_desc);
72178a47101SMike Isely if (ret < 0) {
72249844c29SMike Isely pvr2_trace(PVR2_TRACE_ERROR_LEGS,
72349844c29SMike Isely "device_create_file error: %d",
72449844c29SMike Isely ret);
72578a47101SMike Isely } else {
72678a47101SMike Isely sfp->hdw_desc_created_ok = !0;
72778a47101SMike Isely }
72878a47101SMike Isely
729d855497eSMike Isely pvr2_sysfs_add_controls(sfp);
730d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
731d855497eSMike Isely pvr2_sysfs_add_debugifc(sfp);
732d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
733d855497eSMike Isely }
734d855497eSMike Isely
735d855497eSMike Isely
pvr2_sysfs_internal_check(struct pvr2_channel * chp)736d855497eSMike Isely static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)
737d855497eSMike Isely {
738d855497eSMike Isely struct pvr2_sysfs *sfp;
739d855497eSMike Isely sfp = container_of(chp,struct pvr2_sysfs,channel);
740d855497eSMike Isely if (!sfp->channel.mc_head->disconnect_flag) return;
741d855497eSMike Isely pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);
742d855497eSMike Isely class_dev_destroy(sfp);
743d855497eSMike Isely pvr2_channel_done(&sfp->channel);
744d855497eSMike Isely kfree(sfp);
745d855497eSMike Isely }
746d855497eSMike Isely
747d855497eSMike Isely
pvr2_sysfs_create(struct pvr2_context * mp)7486332a6ceSGreg Kroah-Hartman void pvr2_sysfs_create(struct pvr2_context *mp)
749d855497eSMike Isely {
750d855497eSMike Isely struct pvr2_sysfs *sfp;
751ca545f7cSMike Isely sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
7526332a6ceSGreg Kroah-Hartman if (!sfp)
7536332a6ceSGreg Kroah-Hartman return;
754d855497eSMike Isely pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
755d855497eSMike Isely pvr2_channel_init(&sfp->channel,mp);
756d855497eSMike Isely sfp->channel.check_func = pvr2_sysfs_internal_check;
757d855497eSMike Isely
7586332a6ceSGreg Kroah-Hartman class_dev_create(sfp);
759d855497eSMike Isely }
760d855497eSMike Isely
761d855497eSMike Isely
pvr2_sysfs_class_create(void)7626332a6ceSGreg Kroah-Hartman void pvr2_sysfs_class_create(void)
763d855497eSMike Isely {
7646332a6ceSGreg Kroah-Hartman if (class_register(&pvr2_class))
7656332a6ceSGreg Kroah-Hartman pvr2_sysfs_trace("Registration failed for pvr2_sysfs_class");
766d855497eSMike Isely }
767d855497eSMike Isely
768d855497eSMike Isely
pvr2_sysfs_class_destroy(void)7696332a6ceSGreg Kroah-Hartman void pvr2_sysfs_class_destroy(void)
770d855497eSMike Isely {
7716332a6ceSGreg Kroah-Hartman class_unregister(&pvr2_class);
772d855497eSMike Isely }
773d855497eSMike Isely
774d855497eSMike Isely
775d855497eSMike Isely #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
debuginfo_show(struct device * class_dev,struct device_attribute * attr,char * buf)776c726b65dSTrent Piepho static ssize_t debuginfo_show(struct device *class_dev,
777c726b65dSTrent Piepho struct device_attribute *attr, char *buf)
778d855497eSMike Isely {
779d855497eSMike Isely struct pvr2_sysfs *sfp;
78079510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
781d855497eSMike Isely if (!sfp) return -EINVAL;
782d855497eSMike Isely pvr2_hdw_trigger_module_log(sfp->channel.hdw);
783d855497eSMike Isely return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
784d855497eSMike Isely }
785d855497eSMike Isely
786d855497eSMike Isely
debugcmd_show(struct device * class_dev,struct device_attribute * attr,char * buf)787c726b65dSTrent Piepho static ssize_t debugcmd_show(struct device *class_dev,
788c726b65dSTrent Piepho struct device_attribute *attr, char *buf)
789d855497eSMike Isely {
790d855497eSMike Isely struct pvr2_sysfs *sfp;
79179510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
792d855497eSMike Isely if (!sfp) return -EINVAL;
793d855497eSMike Isely return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
794d855497eSMike Isely }
795d855497eSMike Isely
796d855497eSMike Isely
debugcmd_store(struct device * class_dev,struct device_attribute * attr,const char * buf,size_t count)79754bd5b66SKay Sievers static ssize_t debugcmd_store(struct device *class_dev,
798c726b65dSTrent Piepho struct device_attribute *attr,
799d855497eSMike Isely const char *buf, size_t count)
800d855497eSMike Isely {
801d855497eSMike Isely struct pvr2_sysfs *sfp;
802d855497eSMike Isely int ret;
803d855497eSMike Isely
80479510cdbSGreg Kroah-Hartman sfp = dev_get_drvdata(class_dev);
805d855497eSMike Isely if (!sfp) return -EINVAL;
806d855497eSMike Isely
807d855497eSMike Isely ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
808d855497eSMike Isely if (ret < 0) return ret;
809d855497eSMike Isely return count;
810d855497eSMike Isely }
811d855497eSMike Isely #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
812