Commit | Line | Data |
---|---|---|
d855497e MI |
1 | /* |
2 | * | |
3 | * $Id$ | |
4 | * | |
5 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | * | |
20 | */ | |
21 | ||
d855497e MI |
22 | #include <linux/string.h> |
23 | #include <linux/slab.h> | |
24 | #include <asm/semaphore.h> | |
25 | #include "pvrusb2-sysfs.h" | |
26 | #include "pvrusb2-hdw.h" | |
27 | #include "pvrusb2-debug.h" | |
28 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
29 | #include "pvrusb2-debugifc.h" | |
30 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
31 | ||
32 | #define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__) | |
33 | ||
34 | struct pvr2_sysfs { | |
35 | struct pvr2_channel channel; | |
54bd5b66 | 36 | struct device *class_dev; |
d855497e MI |
37 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC |
38 | struct pvr2_sysfs_debugifc *debugifc; | |
39 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
40 | struct pvr2_sysfs_ctl_item *item_first; | |
41 | struct pvr2_sysfs_ctl_item *item_last; | |
54bd5b66 KS |
42 | struct device_attribute attr_v4l_minor_number; |
43 | struct device_attribute attr_v4l_radio_minor_number; | |
44 | struct device_attribute attr_unit_number; | |
45 | struct device_attribute attr_bus_info; | |
08d41808 | 46 | int v4l_minor_number_created_ok; |
2fdf3d9c | 47 | int v4l_radio_minor_number_created_ok; |
08d41808 | 48 | int unit_number_created_ok; |
31a18547 | 49 | int bus_info_created_ok; |
d855497e MI |
50 | }; |
51 | ||
52 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
53 | struct pvr2_sysfs_debugifc { | |
54bd5b66 KS |
54 | struct device_attribute attr_debugcmd; |
55 | struct device_attribute attr_debuginfo; | |
08d41808 MI |
56 | int debugcmd_created_ok; |
57 | int debuginfo_created_ok; | |
d855497e MI |
58 | }; |
59 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
60 | ||
61 | struct pvr2_sysfs_ctl_item { | |
54bd5b66 KS |
62 | struct device_attribute attr_name; |
63 | struct device_attribute attr_type; | |
64 | struct device_attribute attr_min; | |
65 | struct device_attribute attr_max; | |
66 | struct device_attribute attr_enum; | |
67 | struct device_attribute attr_bits; | |
68 | struct device_attribute attr_val; | |
69 | struct device_attribute attr_custom; | |
d855497e MI |
70 | struct pvr2_ctrl *cptr; |
71 | struct pvr2_sysfs *chptr; | |
72 | struct pvr2_sysfs_ctl_item *item_next; | |
33213963 | 73 | struct attribute *attr_gen[7]; |
d855497e | 74 | struct attribute_group grp; |
08d41808 | 75 | int created_ok; |
d855497e MI |
76 | char name[80]; |
77 | }; | |
78 | ||
79 | struct pvr2_sysfs_class { | |
80 | struct class class; | |
81 | }; | |
82 | ||
54bd5b66 | 83 | static ssize_t show_name(int id,struct device *class_dev,char *buf) |
d855497e MI |
84 | { |
85 | struct pvr2_ctrl *cptr; | |
86 | struct pvr2_sysfs *sfp; | |
87 | const char *name; | |
88 | ||
54bd5b66 | 89 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
90 | if (!sfp) return -EINVAL; |
91 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
92 | if (!cptr) return -EINVAL; | |
93 | ||
94 | name = pvr2_ctrl_get_desc(cptr); | |
95 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name); | |
96 | ||
97 | if (!name) return -EINVAL; | |
98 | ||
99 | return scnprintf(buf,PAGE_SIZE,"%s\n",name); | |
100 | } | |
101 | ||
54bd5b66 | 102 | static ssize_t show_type(int id,struct device *class_dev,char *buf) |
33213963 MI |
103 | { |
104 | struct pvr2_ctrl *cptr; | |
105 | struct pvr2_sysfs *sfp; | |
106 | const char *name; | |
107 | enum pvr2_ctl_type tp; | |
108 | ||
54bd5b66 | 109 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
33213963 MI |
110 | if (!sfp) return -EINVAL; |
111 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
112 | if (!cptr) return -EINVAL; | |
113 | ||
114 | tp = pvr2_ctrl_get_type(cptr); | |
115 | switch (tp) { | |
116 | case pvr2_ctl_int: name = "integer"; break; | |
117 | case pvr2_ctl_enum: name = "enum"; break; | |
118 | case pvr2_ctl_bitmask: name = "bitmask"; break; | |
119 | case pvr2_ctl_bool: name = "boolean"; break; | |
120 | default: name = "?"; break; | |
121 | } | |
122 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name); | |
123 | ||
124 | if (!name) return -EINVAL; | |
125 | ||
126 | return scnprintf(buf,PAGE_SIZE,"%s\n",name); | |
127 | } | |
128 | ||
54bd5b66 | 129 | static ssize_t show_min(int id,struct device *class_dev,char *buf) |
d855497e MI |
130 | { |
131 | struct pvr2_ctrl *cptr; | |
132 | struct pvr2_sysfs *sfp; | |
133 | long val; | |
134 | ||
54bd5b66 | 135 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
136 | if (!sfp) return -EINVAL; |
137 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
138 | if (!cptr) return -EINVAL; | |
139 | val = pvr2_ctrl_get_min(cptr); | |
140 | ||
141 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val); | |
142 | ||
143 | return scnprintf(buf,PAGE_SIZE,"%ld\n",val); | |
144 | } | |
145 | ||
54bd5b66 | 146 | static ssize_t show_max(int id,struct device *class_dev,char *buf) |
d855497e MI |
147 | { |
148 | struct pvr2_ctrl *cptr; | |
149 | struct pvr2_sysfs *sfp; | |
150 | long val; | |
151 | ||
54bd5b66 | 152 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
153 | if (!sfp) return -EINVAL; |
154 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
155 | if (!cptr) return -EINVAL; | |
156 | val = pvr2_ctrl_get_max(cptr); | |
157 | ||
158 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val); | |
159 | ||
160 | return scnprintf(buf,PAGE_SIZE,"%ld\n",val); | |
161 | } | |
162 | ||
54bd5b66 | 163 | static ssize_t show_val_norm(int id,struct device *class_dev,char *buf) |
d855497e MI |
164 | { |
165 | struct pvr2_ctrl *cptr; | |
166 | struct pvr2_sysfs *sfp; | |
167 | int val,ret; | |
168 | unsigned int cnt = 0; | |
169 | ||
54bd5b66 | 170 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
171 | if (!sfp) return -EINVAL; |
172 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
173 | if (!cptr) return -EINVAL; | |
174 | ||
175 | ret = pvr2_ctrl_get_value(cptr,&val); | |
176 | if (ret < 0) return ret; | |
177 | ||
178 | ret = pvr2_ctrl_value_to_sym(cptr,~0,val, | |
179 | buf,PAGE_SIZE-1,&cnt); | |
180 | ||
181 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)", | |
182 | sfp,id,cnt,buf,val); | |
183 | buf[cnt] = '\n'; | |
184 | return cnt+1; | |
185 | } | |
186 | ||
54bd5b66 | 187 | static ssize_t show_val_custom(int id,struct device *class_dev,char *buf) |
d855497e MI |
188 | { |
189 | struct pvr2_ctrl *cptr; | |
190 | struct pvr2_sysfs *sfp; | |
191 | int val,ret; | |
192 | unsigned int cnt = 0; | |
193 | ||
54bd5b66 | 194 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
195 | if (!sfp) return -EINVAL; |
196 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
197 | if (!cptr) return -EINVAL; | |
198 | ||
199 | ret = pvr2_ctrl_get_value(cptr,&val); | |
200 | if (ret < 0) return ret; | |
201 | ||
202 | ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val, | |
203 | buf,PAGE_SIZE-1,&cnt); | |
204 | ||
205 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)", | |
206 | sfp,id,cnt,buf,val); | |
207 | buf[cnt] = '\n'; | |
208 | return cnt+1; | |
209 | } | |
210 | ||
54bd5b66 | 211 | static ssize_t show_enum(int id,struct device *class_dev,char *buf) |
d855497e MI |
212 | { |
213 | struct pvr2_ctrl *cptr; | |
214 | struct pvr2_sysfs *sfp; | |
215 | long val; | |
216 | unsigned int bcnt,ccnt,ecnt; | |
217 | ||
54bd5b66 | 218 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
219 | if (!sfp) return -EINVAL; |
220 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
221 | if (!cptr) return -EINVAL; | |
222 | ecnt = pvr2_ctrl_get_cnt(cptr); | |
223 | bcnt = 0; | |
224 | for (val = 0; val < ecnt; val++) { | |
225 | pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); | |
45886771 | 226 | if (!ccnt) continue; |
d855497e MI |
227 | bcnt += ccnt; |
228 | if (bcnt >= PAGE_SIZE) break; | |
229 | buf[bcnt] = '\n'; | |
230 | bcnt++; | |
231 | } | |
232 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id); | |
233 | return bcnt; | |
234 | } | |
235 | ||
54bd5b66 | 236 | static ssize_t show_bits(int id,struct device *class_dev,char *buf) |
d855497e MI |
237 | { |
238 | struct pvr2_ctrl *cptr; | |
239 | struct pvr2_sysfs *sfp; | |
240 | int valid_bits,msk; | |
241 | unsigned int bcnt,ccnt; | |
242 | ||
54bd5b66 | 243 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
244 | if (!sfp) return -EINVAL; |
245 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
246 | if (!cptr) return -EINVAL; | |
247 | valid_bits = pvr2_ctrl_get_mask(cptr); | |
248 | bcnt = 0; | |
249 | for (msk = 1; valid_bits; msk <<= 1) { | |
250 | if (!(msk & valid_bits)) continue; | |
251 | valid_bits &= ~msk; | |
252 | pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt); | |
253 | bcnt += ccnt; | |
254 | if (bcnt >= PAGE_SIZE) break; | |
255 | buf[bcnt] = '\n'; | |
256 | bcnt++; | |
257 | } | |
258 | pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id); | |
259 | return bcnt; | |
260 | } | |
261 | ||
262 | static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp, | |
263 | const char *buf,unsigned int count) | |
264 | { | |
265 | struct pvr2_ctrl *cptr; | |
266 | int ret; | |
267 | int mask,val; | |
268 | ||
269 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id); | |
270 | if (customfl) { | |
271 | ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val); | |
272 | } else { | |
273 | ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val); | |
274 | } | |
275 | if (ret < 0) return ret; | |
276 | ret = pvr2_ctrl_set_mask_value(cptr,mask,val); | |
277 | pvr2_hdw_commit_ctl(sfp->channel.hdw); | |
278 | return ret; | |
279 | } | |
280 | ||
54bd5b66 | 281 | static ssize_t store_val_norm(int id,struct device *class_dev, |
d855497e MI |
282 | const char *buf,size_t count) |
283 | { | |
284 | struct pvr2_sysfs *sfp; | |
285 | int ret; | |
54bd5b66 | 286 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
287 | ret = store_val_any(id,0,sfp,buf,count); |
288 | if (!ret) ret = count; | |
289 | return ret; | |
290 | } | |
291 | ||
54bd5b66 | 292 | static ssize_t store_val_custom(int id,struct device *class_dev, |
d855497e MI |
293 | const char *buf,size_t count) |
294 | { | |
295 | struct pvr2_sysfs *sfp; | |
296 | int ret; | |
54bd5b66 | 297 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
298 | ret = store_val_any(id,1,sfp,buf,count); |
299 | if (!ret) ret = count; | |
300 | return ret; | |
301 | } | |
302 | ||
303 | /* | |
304 | Mike Isely <isely@pobox.com> 30-April-2005 | |
305 | ||
306 | This next batch of horrible preprocessor hackery is needed because the | |
54bd5b66 | 307 | kernel's device_attribute mechanism fails to pass the actual |
d855497e MI |
308 | attribute through to the show / store functions, which means we have no |
309 | way to package up any attribute-specific parameters, like for example the | |
310 | control id. So we work around this brain-damage by encoding the control | |
311 | id into the show / store functions themselves and pick the function based | |
312 | on the control id we're setting up. These macros try to ease the pain. | |
313 | Yuck. | |
314 | */ | |
315 | ||
316 | #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \ | |
54bd5b66 KS |
317 | static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ |
318 | struct device_attribute *attr, char *buf) \ | |
d855497e MI |
319 | { return sf_name(ctl_id,class_dev,buf); } |
320 | ||
321 | #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \ | |
54bd5b66 KS |
322 | static ssize_t sf_name##_##ctl_id(struct device *class_dev, \ |
323 | struct device_attribute *attr, const char *buf, size_t count) \ | |
d855497e MI |
324 | { return sf_name(ctl_id,class_dev,buf,count); } |
325 | ||
326 | #define CREATE_BATCH(ctl_id) \ | |
327 | CREATE_SHOW_INSTANCE(show_name,ctl_id) \ | |
33213963 | 328 | CREATE_SHOW_INSTANCE(show_type,ctl_id) \ |
d855497e MI |
329 | CREATE_SHOW_INSTANCE(show_min,ctl_id) \ |
330 | CREATE_SHOW_INSTANCE(show_max,ctl_id) \ | |
331 | CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \ | |
332 | CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \ | |
333 | CREATE_SHOW_INSTANCE(show_enum,ctl_id) \ | |
334 | CREATE_SHOW_INSTANCE(show_bits,ctl_id) \ | |
335 | CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \ | |
336 | CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \ | |
337 | ||
338 | CREATE_BATCH(0) | |
339 | CREATE_BATCH(1) | |
340 | CREATE_BATCH(2) | |
341 | CREATE_BATCH(3) | |
342 | CREATE_BATCH(4) | |
343 | CREATE_BATCH(5) | |
344 | CREATE_BATCH(6) | |
345 | CREATE_BATCH(7) | |
346 | CREATE_BATCH(8) | |
347 | CREATE_BATCH(9) | |
348 | CREATE_BATCH(10) | |
349 | CREATE_BATCH(11) | |
350 | CREATE_BATCH(12) | |
351 | CREATE_BATCH(13) | |
352 | CREATE_BATCH(14) | |
353 | CREATE_BATCH(15) | |
354 | CREATE_BATCH(16) | |
355 | CREATE_BATCH(17) | |
356 | CREATE_BATCH(18) | |
357 | CREATE_BATCH(19) | |
358 | CREATE_BATCH(20) | |
359 | CREATE_BATCH(21) | |
360 | CREATE_BATCH(22) | |
361 | CREATE_BATCH(23) | |
362 | CREATE_BATCH(24) | |
363 | CREATE_BATCH(25) | |
364 | CREATE_BATCH(26) | |
365 | CREATE_BATCH(27) | |
366 | CREATE_BATCH(28) | |
367 | CREATE_BATCH(29) | |
368 | CREATE_BATCH(30) | |
369 | CREATE_BATCH(31) | |
370 | CREATE_BATCH(32) | |
371 | CREATE_BATCH(33) | |
3948199e MI |
372 | CREATE_BATCH(34) |
373 | CREATE_BATCH(35) | |
374 | CREATE_BATCH(36) | |
375 | CREATE_BATCH(37) | |
376 | CREATE_BATCH(38) | |
377 | CREATE_BATCH(39) | |
378 | CREATE_BATCH(40) | |
379 | CREATE_BATCH(41) | |
380 | CREATE_BATCH(42) | |
381 | CREATE_BATCH(43) | |
382 | CREATE_BATCH(44) | |
383 | CREATE_BATCH(45) | |
384 | CREATE_BATCH(46) | |
385 | CREATE_BATCH(47) | |
386 | CREATE_BATCH(48) | |
387 | CREATE_BATCH(49) | |
388 | CREATE_BATCH(50) | |
389 | CREATE_BATCH(51) | |
390 | CREATE_BATCH(52) | |
391 | CREATE_BATCH(53) | |
392 | CREATE_BATCH(54) | |
393 | CREATE_BATCH(55) | |
394 | CREATE_BATCH(56) | |
395 | CREATE_BATCH(57) | |
396 | CREATE_BATCH(58) | |
397 | CREATE_BATCH(59) | |
d855497e MI |
398 | |
399 | struct pvr2_sysfs_func_set { | |
54bd5b66 KS |
400 | ssize_t (*show_name)(struct device *, |
401 | struct device_attribute *attr, char *); | |
402 | ssize_t (*show_type)(struct device *, | |
403 | struct device_attribute *attr, char *); | |
404 | ssize_t (*show_min)(struct device *, | |
405 | struct device_attribute *attr, char *); | |
406 | ssize_t (*show_max)(struct device *, | |
407 | struct device_attribute *attr, char *); | |
408 | ssize_t (*show_enum)(struct device *, | |
409 | struct device_attribute *attr, char *); | |
410 | ssize_t (*show_bits)(struct device *, | |
411 | struct device_attribute *attr, char *); | |
412 | ssize_t (*show_val_norm)(struct device *, | |
413 | struct device_attribute *attr, char *); | |
414 | ssize_t (*store_val_norm)(struct device *, | |
415 | struct device_attribute *attr, | |
d855497e | 416 | const char *,size_t); |
54bd5b66 KS |
417 | ssize_t (*show_val_custom)(struct device *, |
418 | struct device_attribute *attr, char *); | |
419 | ssize_t (*store_val_custom)(struct device *, | |
420 | struct device_attribute *attr, | |
d855497e MI |
421 | const char *,size_t); |
422 | }; | |
423 | ||
424 | #define INIT_BATCH(ctl_id) \ | |
425 | [ctl_id] = { \ | |
426 | .show_name = show_name_##ctl_id, \ | |
33213963 | 427 | .show_type = show_type_##ctl_id, \ |
d855497e MI |
428 | .show_min = show_min_##ctl_id, \ |
429 | .show_max = show_max_##ctl_id, \ | |
430 | .show_enum = show_enum_##ctl_id, \ | |
431 | .show_bits = show_bits_##ctl_id, \ | |
432 | .show_val_norm = show_val_norm_##ctl_id, \ | |
433 | .store_val_norm = store_val_norm_##ctl_id, \ | |
434 | .show_val_custom = show_val_custom_##ctl_id, \ | |
435 | .store_val_custom = store_val_custom_##ctl_id, \ | |
436 | } \ | |
437 | ||
438 | static struct pvr2_sysfs_func_set funcs[] = { | |
439 | INIT_BATCH(0), | |
440 | INIT_BATCH(1), | |
441 | INIT_BATCH(2), | |
442 | INIT_BATCH(3), | |
443 | INIT_BATCH(4), | |
444 | INIT_BATCH(5), | |
445 | INIT_BATCH(6), | |
446 | INIT_BATCH(7), | |
447 | INIT_BATCH(8), | |
448 | INIT_BATCH(9), | |
449 | INIT_BATCH(10), | |
450 | INIT_BATCH(11), | |
451 | INIT_BATCH(12), | |
452 | INIT_BATCH(13), | |
453 | INIT_BATCH(14), | |
454 | INIT_BATCH(15), | |
455 | INIT_BATCH(16), | |
456 | INIT_BATCH(17), | |
457 | INIT_BATCH(18), | |
458 | INIT_BATCH(19), | |
459 | INIT_BATCH(20), | |
460 | INIT_BATCH(21), | |
461 | INIT_BATCH(22), | |
462 | INIT_BATCH(23), | |
463 | INIT_BATCH(24), | |
464 | INIT_BATCH(25), | |
465 | INIT_BATCH(26), | |
466 | INIT_BATCH(27), | |
467 | INIT_BATCH(28), | |
468 | INIT_BATCH(29), | |
469 | INIT_BATCH(30), | |
470 | INIT_BATCH(31), | |
471 | INIT_BATCH(32), | |
472 | INIT_BATCH(33), | |
3948199e MI |
473 | INIT_BATCH(34), |
474 | INIT_BATCH(35), | |
475 | INIT_BATCH(36), | |
476 | INIT_BATCH(37), | |
477 | INIT_BATCH(38), | |
478 | INIT_BATCH(39), | |
479 | INIT_BATCH(40), | |
480 | INIT_BATCH(41), | |
481 | INIT_BATCH(42), | |
482 | INIT_BATCH(43), | |
483 | INIT_BATCH(44), | |
484 | INIT_BATCH(45), | |
485 | INIT_BATCH(46), | |
486 | INIT_BATCH(47), | |
487 | INIT_BATCH(48), | |
488 | INIT_BATCH(49), | |
489 | INIT_BATCH(50), | |
490 | INIT_BATCH(51), | |
491 | INIT_BATCH(52), | |
492 | INIT_BATCH(53), | |
493 | INIT_BATCH(54), | |
494 | INIT_BATCH(55), | |
495 | INIT_BATCH(56), | |
496 | INIT_BATCH(57), | |
497 | INIT_BATCH(58), | |
498 | INIT_BATCH(59), | |
d855497e MI |
499 | }; |
500 | ||
501 | ||
502 | static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) | |
503 | { | |
504 | struct pvr2_sysfs_ctl_item *cip; | |
505 | struct pvr2_sysfs_func_set *fp; | |
506 | struct pvr2_ctrl *cptr; | |
507 | unsigned int cnt,acnt; | |
08d41808 | 508 | int ret; |
d855497e | 509 | |
eca8ebfc | 510 | if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) { |
d855497e MI |
511 | return; |
512 | } | |
513 | ||
514 | fp = funcs + ctl_id; | |
515 | cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id); | |
516 | if (!cptr) return; | |
517 | ||
ca545f7c | 518 | cip = kzalloc(sizeof(*cip),GFP_KERNEL); |
d855497e | 519 | if (!cip) return; |
d855497e MI |
520 | pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip); |
521 | ||
522 | cip->cptr = cptr; | |
523 | ||
524 | cip->chptr = sfp; | |
a0fd1cb1 | 525 | cip->item_next = NULL; |
d855497e MI |
526 | if (sfp->item_last) { |
527 | sfp->item_last->item_next = cip; | |
528 | } else { | |
529 | sfp->item_first = cip; | |
530 | } | |
531 | sfp->item_last = cip; | |
532 | ||
d855497e MI |
533 | cip->attr_name.attr.name = "name"; |
534 | cip->attr_name.attr.mode = S_IRUGO; | |
535 | cip->attr_name.show = fp->show_name; | |
536 | ||
33213963 MI |
537 | cip->attr_type.attr.name = "type"; |
538 | cip->attr_type.attr.mode = S_IRUGO; | |
539 | cip->attr_type.show = fp->show_type; | |
540 | ||
d855497e MI |
541 | cip->attr_min.attr.name = "min_val"; |
542 | cip->attr_min.attr.mode = S_IRUGO; | |
543 | cip->attr_min.show = fp->show_min; | |
544 | ||
d855497e MI |
545 | cip->attr_max.attr.name = "max_val"; |
546 | cip->attr_max.attr.mode = S_IRUGO; | |
547 | cip->attr_max.show = fp->show_max; | |
548 | ||
d855497e MI |
549 | cip->attr_val.attr.name = "cur_val"; |
550 | cip->attr_val.attr.mode = S_IRUGO; | |
551 | ||
d855497e MI |
552 | cip->attr_custom.attr.name = "custom_val"; |
553 | cip->attr_custom.attr.mode = S_IRUGO; | |
554 | ||
d855497e MI |
555 | cip->attr_enum.attr.name = "enum_val"; |
556 | cip->attr_enum.attr.mode = S_IRUGO; | |
557 | cip->attr_enum.show = fp->show_enum; | |
558 | ||
d855497e MI |
559 | cip->attr_bits.attr.name = "bit_val"; |
560 | cip->attr_bits.attr.mode = S_IRUGO; | |
561 | cip->attr_bits.show = fp->show_bits; | |
562 | ||
563 | if (pvr2_ctrl_is_writable(cptr)) { | |
564 | cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP; | |
565 | cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP; | |
566 | } | |
567 | ||
568 | acnt = 0; | |
569 | cip->attr_gen[acnt++] = &cip->attr_name.attr; | |
33213963 | 570 | cip->attr_gen[acnt++] = &cip->attr_type.attr; |
d855497e MI |
571 | cip->attr_gen[acnt++] = &cip->attr_val.attr; |
572 | cip->attr_val.show = fp->show_val_norm; | |
573 | cip->attr_val.store = fp->store_val_norm; | |
574 | if (pvr2_ctrl_has_custom_symbols(cptr)) { | |
575 | cip->attr_gen[acnt++] = &cip->attr_custom.attr; | |
576 | cip->attr_custom.show = fp->show_val_custom; | |
577 | cip->attr_custom.store = fp->store_val_custom; | |
578 | } | |
579 | switch (pvr2_ctrl_get_type(cptr)) { | |
580 | case pvr2_ctl_enum: | |
581 | // Control is an enumeration | |
582 | cip->attr_gen[acnt++] = &cip->attr_enum.attr; | |
583 | break; | |
584 | case pvr2_ctl_int: | |
585 | // Control is an integer | |
586 | cip->attr_gen[acnt++] = &cip->attr_min.attr; | |
587 | cip->attr_gen[acnt++] = &cip->attr_max.attr; | |
588 | break; | |
589 | case pvr2_ctl_bitmask: | |
590 | // Control is an bitmask | |
591 | cip->attr_gen[acnt++] = &cip->attr_bits.attr; | |
592 | break; | |
593 | default: break; | |
594 | } | |
595 | ||
596 | cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s", | |
597 | pvr2_ctrl_get_name(cptr)); | |
598 | cip->name[cnt] = 0; | |
599 | cip->grp.name = cip->name; | |
600 | cip->grp.attrs = cip->attr_gen; | |
601 | ||
08d41808 MI |
602 | ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp); |
603 | if (ret) { | |
604 | printk(KERN_WARNING "%s: sysfs_create_group error: %d\n", | |
605 | __FUNCTION__, ret); | |
606 | return; | |
607 | } | |
608 | cip->created_ok = !0; | |
d855497e MI |
609 | } |
610 | ||
611 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
c726b65d TP |
612 | static ssize_t debuginfo_show(struct device *, struct device_attribute *, |
613 | char *); | |
614 | static ssize_t debugcmd_show(struct device *, struct device_attribute *, | |
615 | char *); | |
616 | static ssize_t debugcmd_store(struct device *, struct device_attribute *, | |
617 | const char *, size_t count); | |
d855497e MI |
618 | |
619 | static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp) | |
620 | { | |
621 | struct pvr2_sysfs_debugifc *dip; | |
3117beec MK |
622 | int ret; |
623 | ||
ca545f7c | 624 | dip = kzalloc(sizeof(*dip),GFP_KERNEL); |
d855497e | 625 | if (!dip) return; |
d855497e MI |
626 | dip->attr_debugcmd.attr.name = "debugcmd"; |
627 | dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP; | |
628 | dip->attr_debugcmd.show = debugcmd_show; | |
629 | dip->attr_debugcmd.store = debugcmd_store; | |
d855497e MI |
630 | dip->attr_debuginfo.attr.name = "debuginfo"; |
631 | dip->attr_debuginfo.attr.mode = S_IRUGO; | |
632 | dip->attr_debuginfo.show = debuginfo_show; | |
633 | sfp->debugifc = dip; | |
54bd5b66 | 634 | ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd); |
08d41808 | 635 | if (ret < 0) { |
54bd5b66 | 636 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
3117beec | 637 | __FUNCTION__, ret); |
08d41808 MI |
638 | } else { |
639 | dip->debugcmd_created_ok = !0; | |
640 | } | |
54bd5b66 | 641 | ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo); |
08d41808 | 642 | if (ret < 0) { |
54bd5b66 | 643 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
3117beec | 644 | __FUNCTION__, ret); |
08d41808 MI |
645 | } else { |
646 | dip->debuginfo_created_ok = !0; | |
647 | } | |
d855497e MI |
648 | } |
649 | ||
650 | ||
651 | static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp) | |
652 | { | |
653 | if (!sfp->debugifc) return; | |
08d41808 | 654 | if (sfp->debugifc->debuginfo_created_ok) { |
54bd5b66 | 655 | device_remove_file(sfp->class_dev, |
08d41808 MI |
656 | &sfp->debugifc->attr_debuginfo); |
657 | } | |
658 | if (sfp->debugifc->debugcmd_created_ok) { | |
54bd5b66 | 659 | device_remove_file(sfp->class_dev, |
08d41808 MI |
660 | &sfp->debugifc->attr_debugcmd); |
661 | } | |
d855497e | 662 | kfree(sfp->debugifc); |
a0fd1cb1 | 663 | sfp->debugifc = NULL; |
d855497e MI |
664 | } |
665 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
666 | ||
667 | ||
668 | static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp) | |
669 | { | |
670 | unsigned int idx,cnt; | |
671 | cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw); | |
672 | for (idx = 0; idx < cnt; idx++) { | |
673 | pvr2_sysfs_add_control(sfp,idx); | |
674 | } | |
675 | } | |
676 | ||
677 | ||
678 | static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp) | |
679 | { | |
680 | struct pvr2_sysfs_ctl_item *cip1,*cip2; | |
681 | for (cip1 = sfp->item_first; cip1; cip1 = cip2) { | |
682 | cip2 = cip1->item_next; | |
08d41808 MI |
683 | if (cip1->created_ok) { |
684 | sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp); | |
685 | } | |
d855497e MI |
686 | pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1); |
687 | kfree(cip1); | |
688 | } | |
689 | } | |
690 | ||
691 | ||
692 | static void pvr2_sysfs_class_release(struct class *class) | |
693 | { | |
694 | struct pvr2_sysfs_class *clp; | |
695 | clp = container_of(class,struct pvr2_sysfs_class,class); | |
696 | pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp); | |
697 | kfree(clp); | |
698 | } | |
699 | ||
700 | ||
54bd5b66 | 701 | static void pvr2_sysfs_release(struct device *class_dev) |
d855497e MI |
702 | { |
703 | pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev); | |
704 | kfree(class_dev); | |
705 | } | |
706 | ||
707 | ||
708 | static void class_dev_destroy(struct pvr2_sysfs *sfp) | |
709 | { | |
710 | if (!sfp->class_dev) return; | |
711 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
712 | pvr2_sysfs_tear_down_debugifc(sfp); | |
713 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
714 | pvr2_sysfs_tear_down_controls(sfp); | |
31a18547 | 715 | if (sfp->bus_info_created_ok) { |
54bd5b66 | 716 | device_remove_file(sfp->class_dev, |
31a18547 MI |
717 | &sfp->attr_bus_info); |
718 | } | |
08d41808 | 719 | if (sfp->v4l_minor_number_created_ok) { |
54bd5b66 | 720 | device_remove_file(sfp->class_dev, |
08d41808 MI |
721 | &sfp->attr_v4l_minor_number); |
722 | } | |
2fdf3d9c | 723 | if (sfp->v4l_radio_minor_number_created_ok) { |
54bd5b66 | 724 | device_remove_file(sfp->class_dev, |
2fdf3d9c PK |
725 | &sfp->attr_v4l_radio_minor_number); |
726 | } | |
08d41808 | 727 | if (sfp->unit_number_created_ok) { |
54bd5b66 | 728 | device_remove_file(sfp->class_dev, |
08d41808 MI |
729 | &sfp->attr_unit_number); |
730 | } | |
d855497e | 731 | pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev); |
54bd5b66 KS |
732 | sfp->class_dev->driver_data = NULL; |
733 | device_unregister(sfp->class_dev); | |
a0fd1cb1 | 734 | sfp->class_dev = NULL; |
d855497e MI |
735 | } |
736 | ||
737 | ||
54bd5b66 KS |
738 | static ssize_t v4l_minor_number_show(struct device *class_dev, |
739 | struct device_attribute *attr, char *buf) | |
d855497e MI |
740 | { |
741 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 742 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
743 | if (!sfp) return -EINVAL; |
744 | return scnprintf(buf,PAGE_SIZE,"%d\n", | |
fd5a75fe | 745 | pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, |
8079384e | 746 | pvr2_v4l_type_video)); |
2fdf3d9c PK |
747 | } |
748 | ||
749 | ||
54bd5b66 KS |
750 | static ssize_t bus_info_show(struct device *class_dev, |
751 | struct device_attribute *attr, char *buf) | |
31a18547 MI |
752 | { |
753 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 754 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
31a18547 MI |
755 | if (!sfp) return -EINVAL; |
756 | return scnprintf(buf,PAGE_SIZE,"%s\n", | |
757 | pvr2_hdw_get_bus_info(sfp->channel.hdw)); | |
758 | } | |
759 | ||
760 | ||
54bd5b66 KS |
761 | static ssize_t v4l_radio_minor_number_show(struct device *class_dev, |
762 | struct device_attribute *attr, | |
2fdf3d9c PK |
763 | char *buf) |
764 | { | |
765 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 766 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
2fdf3d9c PK |
767 | if (!sfp) return -EINVAL; |
768 | return scnprintf(buf,PAGE_SIZE,"%d\n", | |
fd5a75fe | 769 | pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw, |
8079384e | 770 | pvr2_v4l_type_radio)); |
d855497e MI |
771 | } |
772 | ||
773 | ||
54bd5b66 KS |
774 | static ssize_t unit_number_show(struct device *class_dev, |
775 | struct device_attribute *attr, char *buf) | |
d855497e MI |
776 | { |
777 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 778 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
779 | if (!sfp) return -EINVAL; |
780 | return scnprintf(buf,PAGE_SIZE,"%d\n", | |
781 | pvr2_hdw_get_unit_number(sfp->channel.hdw)); | |
782 | } | |
783 | ||
784 | ||
785 | static void class_dev_create(struct pvr2_sysfs *sfp, | |
786 | struct pvr2_sysfs_class *class_ptr) | |
787 | { | |
788 | struct usb_device *usb_dev; | |
54bd5b66 | 789 | struct device *class_dev; |
3117beec MK |
790 | int ret; |
791 | ||
d855497e MI |
792 | usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw); |
793 | if (!usb_dev) return; | |
ca545f7c | 794 | class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL); |
d855497e | 795 | if (!class_dev) return; |
d855497e MI |
796 | |
797 | pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); | |
798 | ||
799 | class_dev->class = &class_ptr->class; | |
800 | if (pvr2_hdw_get_sn(sfp->channel.hdw)) { | |
54bd5b66 | 801 | snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu", |
d855497e MI |
802 | pvr2_hdw_get_sn(sfp->channel.hdw)); |
803 | } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { | |
54bd5b66 | 804 | snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c", |
d855497e MI |
805 | pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); |
806 | } else { | |
807 | kfree(class_dev); | |
808 | return; | |
809 | } | |
810 | ||
54bd5b66 | 811 | class_dev->parent = &usb_dev->dev; |
d855497e MI |
812 | |
813 | sfp->class_dev = class_dev; | |
54bd5b66 KS |
814 | class_dev->driver_data = sfp; |
815 | ret = device_register(class_dev); | |
3117beec | 816 | if (ret) { |
54bd5b66 | 817 | printk(KERN_ERR "%s: device_register failed\n", |
3117beec MK |
818 | __FUNCTION__); |
819 | kfree(class_dev); | |
820 | return; | |
821 | } | |
d855497e | 822 | |
d855497e MI |
823 | sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number"; |
824 | sfp->attr_v4l_minor_number.attr.mode = S_IRUGO; | |
825 | sfp->attr_v4l_minor_number.show = v4l_minor_number_show; | |
a0fd1cb1 | 826 | sfp->attr_v4l_minor_number.store = NULL; |
54bd5b66 | 827 | ret = device_create_file(sfp->class_dev, |
08d41808 MI |
828 | &sfp->attr_v4l_minor_number); |
829 | if (ret < 0) { | |
54bd5b66 | 830 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
3117beec | 831 | __FUNCTION__, ret); |
08d41808 MI |
832 | } else { |
833 | sfp->v4l_minor_number_created_ok = !0; | |
834 | } | |
3117beec | 835 | |
2fdf3d9c PK |
836 | sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number"; |
837 | sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO; | |
838 | sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show; | |
839 | sfp->attr_v4l_radio_minor_number.store = NULL; | |
54bd5b66 | 840 | ret = device_create_file(sfp->class_dev, |
2fdf3d9c PK |
841 | &sfp->attr_v4l_radio_minor_number); |
842 | if (ret < 0) { | |
54bd5b66 | 843 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
2fdf3d9c PK |
844 | __FUNCTION__, ret); |
845 | } else { | |
846 | sfp->v4l_radio_minor_number_created_ok = !0; | |
847 | } | |
848 | ||
d855497e MI |
849 | sfp->attr_unit_number.attr.name = "unit_number"; |
850 | sfp->attr_unit_number.attr.mode = S_IRUGO; | |
851 | sfp->attr_unit_number.show = unit_number_show; | |
a0fd1cb1 | 852 | sfp->attr_unit_number.store = NULL; |
54bd5b66 | 853 | ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number); |
08d41808 | 854 | if (ret < 0) { |
54bd5b66 | 855 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
3117beec | 856 | __FUNCTION__, ret); |
08d41808 MI |
857 | } else { |
858 | sfp->unit_number_created_ok = !0; | |
859 | } | |
d855497e | 860 | |
31a18547 MI |
861 | sfp->attr_bus_info.attr.name = "bus_info_str"; |
862 | sfp->attr_bus_info.attr.mode = S_IRUGO; | |
863 | sfp->attr_bus_info.show = bus_info_show; | |
864 | sfp->attr_bus_info.store = NULL; | |
54bd5b66 | 865 | ret = device_create_file(sfp->class_dev, |
31a18547 MI |
866 | &sfp->attr_bus_info); |
867 | if (ret < 0) { | |
54bd5b66 | 868 | printk(KERN_WARNING "%s: device_create_file error: %d\n", |
31a18547 MI |
869 | __FUNCTION__, ret); |
870 | } else { | |
871 | sfp->bus_info_created_ok = !0; | |
872 | } | |
873 | ||
d855497e MI |
874 | pvr2_sysfs_add_controls(sfp); |
875 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
876 | pvr2_sysfs_add_debugifc(sfp); | |
877 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
878 | } | |
879 | ||
880 | ||
881 | static void pvr2_sysfs_internal_check(struct pvr2_channel *chp) | |
882 | { | |
883 | struct pvr2_sysfs *sfp; | |
884 | sfp = container_of(chp,struct pvr2_sysfs,channel); | |
885 | if (!sfp->channel.mc_head->disconnect_flag) return; | |
886 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp); | |
887 | class_dev_destroy(sfp); | |
888 | pvr2_channel_done(&sfp->channel); | |
889 | kfree(sfp); | |
890 | } | |
891 | ||
892 | ||
893 | struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp, | |
894 | struct pvr2_sysfs_class *class_ptr) | |
895 | { | |
896 | struct pvr2_sysfs *sfp; | |
ca545f7c | 897 | sfp = kzalloc(sizeof(*sfp),GFP_KERNEL); |
d855497e | 898 | if (!sfp) return sfp; |
d855497e MI |
899 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp); |
900 | pvr2_channel_init(&sfp->channel,mp); | |
901 | sfp->channel.check_func = pvr2_sysfs_internal_check; | |
902 | ||
903 | class_dev_create(sfp,class_ptr); | |
904 | return sfp; | |
905 | } | |
906 | ||
907 | ||
7eff2e7a KS |
908 | static int pvr2_sysfs_hotplug(struct device *d, |
909 | struct kobj_uevent_env *env) | |
d855497e MI |
910 | { |
911 | /* Even though we don't do anything here, we still need this function | |
912 | because sysfs will still try to call it. */ | |
913 | return 0; | |
914 | } | |
915 | ||
916 | struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) | |
917 | { | |
918 | struct pvr2_sysfs_class *clp; | |
ca545f7c | 919 | clp = kzalloc(sizeof(*clp),GFP_KERNEL); |
d855497e | 920 | if (!clp) return clp; |
d855497e MI |
921 | pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp); |
922 | clp->class.name = "pvrusb2"; | |
923 | clp->class.class_release = pvr2_sysfs_class_release; | |
54bd5b66 KS |
924 | clp->class.dev_release = pvr2_sysfs_release; |
925 | clp->class.dev_uevent = pvr2_sysfs_hotplug; | |
d855497e MI |
926 | if (class_register(&clp->class)) { |
927 | pvr2_sysfs_trace( | |
928 | "Registration failed for pvr2_sysfs_class id=%p",clp); | |
929 | kfree(clp); | |
a0fd1cb1 | 930 | clp = NULL; |
d855497e MI |
931 | } |
932 | return clp; | |
933 | } | |
934 | ||
935 | ||
936 | void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) | |
937 | { | |
938 | class_unregister(&clp->class); | |
939 | } | |
940 | ||
941 | ||
942 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | |
c726b65d TP |
943 | static ssize_t debuginfo_show(struct device *class_dev, |
944 | struct device_attribute *attr, char *buf) | |
d855497e MI |
945 | { |
946 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 947 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
948 | if (!sfp) return -EINVAL; |
949 | pvr2_hdw_trigger_module_log(sfp->channel.hdw); | |
950 | return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE); | |
951 | } | |
952 | ||
953 | ||
c726b65d TP |
954 | static ssize_t debugcmd_show(struct device *class_dev, |
955 | struct device_attribute *attr, char *buf) | |
d855497e MI |
956 | { |
957 | struct pvr2_sysfs *sfp; | |
54bd5b66 | 958 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
959 | if (!sfp) return -EINVAL; |
960 | return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE); | |
961 | } | |
962 | ||
963 | ||
54bd5b66 | 964 | static ssize_t debugcmd_store(struct device *class_dev, |
c726b65d | 965 | struct device_attribute *attr, |
54bd5b66 | 966 | const char *buf, size_t count) |
d855497e MI |
967 | { |
968 | struct pvr2_sysfs *sfp; | |
969 | int ret; | |
970 | ||
54bd5b66 | 971 | sfp = (struct pvr2_sysfs *)class_dev->driver_data; |
d855497e MI |
972 | if (!sfp) return -EINVAL; |
973 | ||
974 | ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count); | |
975 | if (ret < 0) return ret; | |
976 | return count; | |
977 | } | |
978 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | |
979 | ||
980 | ||
981 | /* | |
982 | Stuff for Emacs to see, in order to encourage consistent editing style: | |
983 | *** Local Variables: *** | |
984 | *** mode: c *** | |
985 | *** fill-column: 75 *** | |
986 | *** tab-width: 8 *** | |
987 | *** c-basic-offset: 8 *** | |
988 | *** End: *** | |
989 | */ |