pvrusb2-sysfs.c 27.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
 *
 *  $Id$
 *
 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/string.h>
#include <linux/slab.h>
#include <asm/semaphore.h>
#include "pvrusb2-sysfs.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
#include "pvrusb2-debugifc.h"
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */

#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)

struct pvr2_sysfs {
	struct pvr2_channel channel;
36
	struct device *class_dev;
37 38 39 40 41
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
	struct pvr2_sysfs_debugifc *debugifc;
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
	struct pvr2_sysfs_ctl_item *item_first;
	struct pvr2_sysfs_ctl_item *item_last;
42 43 44 45
	struct device_attribute attr_v4l_minor_number;
	struct device_attribute attr_v4l_radio_minor_number;
	struct device_attribute attr_unit_number;
	struct device_attribute attr_bus_info;
46 47
	struct device_attribute attr_hdw_name;
	struct device_attribute attr_hdw_desc;
48
	int v4l_minor_number_created_ok;
49
	int v4l_radio_minor_number_created_ok;
50
	int unit_number_created_ok;
51
	int bus_info_created_ok;
52 53
	int hdw_name_created_ok;
	int hdw_desc_created_ok;
54 55 56 57
};

#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
58 59
	struct device_attribute attr_debugcmd;
	struct device_attribute attr_debuginfo;
60 61
	int debugcmd_created_ok;
	int debuginfo_created_ok;
62 63 64 65
};
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */

struct pvr2_sysfs_ctl_item {
66 67 68 69 70 71 72 73
	struct device_attribute attr_name;
	struct device_attribute attr_type;
	struct device_attribute attr_min;
	struct device_attribute attr_max;
	struct device_attribute attr_enum;
	struct device_attribute attr_bits;
	struct device_attribute attr_val;
	struct device_attribute attr_custom;
74 75 76
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *chptr;
	struct pvr2_sysfs_ctl_item *item_next;
77
	struct attribute *attr_gen[7];
78
	struct attribute_group grp;
79
	int created_ok;
80 81 82 83 84 85 86
	char name[80];
};

struct pvr2_sysfs_class {
	struct class class;
};

87
static ssize_t show_name(int id,struct device *class_dev,char *buf)
88 89 90 91 92
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	const char *name;

93
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
94 95 96 97 98 99 100 101 102 103 104 105
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;

	name = pvr2_ctrl_get_desc(cptr);
	pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);

	if (!name) return -EINVAL;

	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}

106
static ssize_t show_type(int id,struct device *class_dev,char *buf)
107 108 109 110 111 112
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	const char *name;
	enum pvr2_ctl_type tp;

113
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;

	tp = pvr2_ctrl_get_type(cptr);
	switch (tp) {
	case pvr2_ctl_int: name = "integer"; break;
	case pvr2_ctl_enum: name = "enum"; break;
	case pvr2_ctl_bitmask: name = "bitmask"; break;
	case pvr2_ctl_bool: name = "boolean"; break;
	default: name = "?"; break;
	}
	pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);

	if (!name) return -EINVAL;

	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}

133
static ssize_t show_min(int id,struct device *class_dev,char *buf)
134 135 136 137 138
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	long val;

139
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
140 141 142 143 144 145 146 147 148 149
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;
	val = pvr2_ctrl_get_min(cptr);

	pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);

	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}

150
static ssize_t show_max(int id,struct device *class_dev,char *buf)
151 152 153 154 155
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	long val;

156
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
157 158 159 160 161 162 163 164 165 166
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;
	val = pvr2_ctrl_get_max(cptr);

	pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);

	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}

167
static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
168 169 170 171 172 173
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	int val,ret;
	unsigned int cnt = 0;

174
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;

	ret = pvr2_ctrl_get_value(cptr,&val);
	if (ret < 0) return ret;

	ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
				     buf,PAGE_SIZE-1,&cnt);

	pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
			 sfp,id,cnt,buf,val);
	buf[cnt] = '\n';
	return cnt+1;
}

191
static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
192 193 194 195 196 197
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	int val,ret;
	unsigned int cnt = 0;

198
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;

	ret = pvr2_ctrl_get_value(cptr,&val);
	if (ret < 0) return ret;

	ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
					    buf,PAGE_SIZE-1,&cnt);

	pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
			 sfp,id,cnt,buf,val);
	buf[cnt] = '\n';
	return cnt+1;
}

215
static ssize_t show_enum(int id,struct device *class_dev,char *buf)
216 217 218 219 220 221
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	long val;
	unsigned int bcnt,ccnt,ecnt;

222
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
223 224 225 226 227 228 229
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;
	ecnt = pvr2_ctrl_get_cnt(cptr);
	bcnt = 0;
	for (val = 0; val < ecnt; val++) {
		pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
230
		if (!ccnt) continue;
231 232 233 234 235 236 237 238 239
		bcnt += ccnt;
		if (bcnt >= PAGE_SIZE) break;
		buf[bcnt] = '\n';
		bcnt++;
	}
	pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
	return bcnt;
}

240
static ssize_t show_bits(int id,struct device *class_dev,char *buf)
241 242 243 244 245 246
{
	struct pvr2_ctrl *cptr;
	struct pvr2_sysfs *sfp;
	int valid_bits,msk;
	unsigned int bcnt,ccnt;

247
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
	if (!sfp) return -EINVAL;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (!cptr) return -EINVAL;
	valid_bits = pvr2_ctrl_get_mask(cptr);
	bcnt = 0;
	for (msk = 1; valid_bits; msk <<= 1) {
		if (!(msk & valid_bits)) continue;
		valid_bits &= ~msk;
		pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
		bcnt += ccnt;
		if (bcnt >= PAGE_SIZE) break;
		buf[bcnt] = '\n';
		bcnt++;
	}
	pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
	return bcnt;
}

static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
			 const char *buf,unsigned int count)
{
	struct pvr2_ctrl *cptr;
	int ret;
	int mask,val;

	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
	if (customfl) {
		ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
	} else {
		ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
	}
	if (ret < 0) return ret;
	ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
	pvr2_hdw_commit_ctl(sfp->channel.hdw);
	return ret;
}

285
static ssize_t store_val_norm(int id,struct device *class_dev,
286 287 288 289
			     const char *buf,size_t count)
{
	struct pvr2_sysfs *sfp;
	int ret;
290
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
291 292 293 294 295
	ret = store_val_any(id,0,sfp,buf,count);
	if (!ret) ret = count;
	return ret;
}

296
static ssize_t store_val_custom(int id,struct device *class_dev,
297 298 299 300
				const char *buf,size_t count)
{
	struct pvr2_sysfs *sfp;
	int ret;
301
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
302 303 304 305 306 307 308 309 310
	ret = store_val_any(id,1,sfp,buf,count);
	if (!ret) ret = count;
	return ret;
}

/*
  Mike Isely <isely@pobox.com> 30-April-2005

  This next batch of horrible preprocessor hackery is needed because the
311
  kernel's device_attribute mechanism fails to pass the actual
312 313 314 315 316 317 318 319 320
  attribute through to the show / store functions, which means we have no
  way to package up any attribute-specific parameters, like for example the
  control id.  So we work around this brain-damage by encoding the control
  id into the show / store functions themselves and pick the function based
  on the control id we're setting up.  These macros try to ease the pain.
  Yuck.
*/

#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
321 322
static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
struct device_attribute *attr, char *buf) \
323 324 325
{ return sf_name(ctl_id,class_dev,buf); }

#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
326 327
static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
struct device_attribute *attr, const char *buf, size_t count) \
328 329 330 331
{ return sf_name(ctl_id,class_dev,buf,count); }

#define CREATE_BATCH(ctl_id) \
CREATE_SHOW_INSTANCE(show_name,ctl_id) \
332
CREATE_SHOW_INSTANCE(show_type,ctl_id) \
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
CREATE_SHOW_INSTANCE(show_min,ctl_id) \
CREATE_SHOW_INSTANCE(show_max,ctl_id) \
CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \

CREATE_BATCH(0)
CREATE_BATCH(1)
CREATE_BATCH(2)
CREATE_BATCH(3)
CREATE_BATCH(4)
CREATE_BATCH(5)
CREATE_BATCH(6)
CREATE_BATCH(7)
CREATE_BATCH(8)
CREATE_BATCH(9)
CREATE_BATCH(10)
CREATE_BATCH(11)
CREATE_BATCH(12)
CREATE_BATCH(13)
CREATE_BATCH(14)
CREATE_BATCH(15)
CREATE_BATCH(16)
CREATE_BATCH(17)
CREATE_BATCH(18)
CREATE_BATCH(19)
CREATE_BATCH(20)
CREATE_BATCH(21)
CREATE_BATCH(22)
CREATE_BATCH(23)
CREATE_BATCH(24)
CREATE_BATCH(25)
CREATE_BATCH(26)
CREATE_BATCH(27)
CREATE_BATCH(28)
CREATE_BATCH(29)
CREATE_BATCH(30)
CREATE_BATCH(31)
CREATE_BATCH(32)
CREATE_BATCH(33)
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
CREATE_BATCH(34)
CREATE_BATCH(35)
CREATE_BATCH(36)
CREATE_BATCH(37)
CREATE_BATCH(38)
CREATE_BATCH(39)
CREATE_BATCH(40)
CREATE_BATCH(41)
CREATE_BATCH(42)
CREATE_BATCH(43)
CREATE_BATCH(44)
CREATE_BATCH(45)
CREATE_BATCH(46)
CREATE_BATCH(47)
CREATE_BATCH(48)
CREATE_BATCH(49)
CREATE_BATCH(50)
CREATE_BATCH(51)
CREATE_BATCH(52)
CREATE_BATCH(53)
CREATE_BATCH(54)
CREATE_BATCH(55)
CREATE_BATCH(56)
CREATE_BATCH(57)
CREATE_BATCH(58)
CREATE_BATCH(59)
402 403

struct pvr2_sysfs_func_set {
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	ssize_t (*show_name)(struct device *,
			     struct device_attribute *attr, char *);
	ssize_t (*show_type)(struct device *,
			     struct device_attribute *attr, char *);
	ssize_t (*show_min)(struct device *,
			    struct device_attribute *attr, char *);
	ssize_t (*show_max)(struct device *,
			    struct device_attribute *attr, char *);
	ssize_t (*show_enum)(struct device *,
			     struct device_attribute *attr, char *);
	ssize_t (*show_bits)(struct device *,
			     struct device_attribute *attr, char *);
	ssize_t (*show_val_norm)(struct device *,
				 struct device_attribute *attr, char *);
	ssize_t (*store_val_norm)(struct device *,
				  struct device_attribute *attr,
420
				  const char *,size_t);
421 422 423 424
	ssize_t (*show_val_custom)(struct device *,
				   struct device_attribute *attr, char *);
	ssize_t (*store_val_custom)(struct device *,
				    struct device_attribute *attr,
425 426 427 428 429 430
				    const char *,size_t);
};

#define INIT_BATCH(ctl_id) \
[ctl_id] = { \
    .show_name = show_name_##ctl_id, \
431
    .show_type = show_type_##ctl_id, \
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    .show_min = show_min_##ctl_id, \
    .show_max = show_max_##ctl_id, \
    .show_enum = show_enum_##ctl_id, \
    .show_bits = show_bits_##ctl_id, \
    .show_val_norm = show_val_norm_##ctl_id, \
    .store_val_norm = store_val_norm_##ctl_id, \
    .show_val_custom = show_val_custom_##ctl_id, \
    .store_val_custom = store_val_custom_##ctl_id, \
} \

static struct pvr2_sysfs_func_set funcs[] = {
	INIT_BATCH(0),
	INIT_BATCH(1),
	INIT_BATCH(2),
	INIT_BATCH(3),
	INIT_BATCH(4),
	INIT_BATCH(5),
	INIT_BATCH(6),
	INIT_BATCH(7),
	INIT_BATCH(8),
	INIT_BATCH(9),
	INIT_BATCH(10),
	INIT_BATCH(11),
	INIT_BATCH(12),
	INIT_BATCH(13),
	INIT_BATCH(14),
	INIT_BATCH(15),
	INIT_BATCH(16),
	INIT_BATCH(17),
	INIT_BATCH(18),
	INIT_BATCH(19),
	INIT_BATCH(20),
	INIT_BATCH(21),
	INIT_BATCH(22),
	INIT_BATCH(23),
	INIT_BATCH(24),
	INIT_BATCH(25),
	INIT_BATCH(26),
	INIT_BATCH(27),
	INIT_BATCH(28),
	INIT_BATCH(29),
	INIT_BATCH(30),
	INIT_BATCH(31),
	INIT_BATCH(32),
	INIT_BATCH(33),
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
	INIT_BATCH(34),
	INIT_BATCH(35),
	INIT_BATCH(36),
	INIT_BATCH(37),
	INIT_BATCH(38),
	INIT_BATCH(39),
	INIT_BATCH(40),
	INIT_BATCH(41),
	INIT_BATCH(42),
	INIT_BATCH(43),
	INIT_BATCH(44),
	INIT_BATCH(45),
	INIT_BATCH(46),
	INIT_BATCH(47),
	INIT_BATCH(48),
	INIT_BATCH(49),
	INIT_BATCH(50),
	INIT_BATCH(51),
	INIT_BATCH(52),
	INIT_BATCH(53),
	INIT_BATCH(54),
	INIT_BATCH(55),
	INIT_BATCH(56),
	INIT_BATCH(57),
	INIT_BATCH(58),
	INIT_BATCH(59),
503 504 505 506 507 508 509 510 511
};


static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
{
	struct pvr2_sysfs_ctl_item *cip;
	struct pvr2_sysfs_func_set *fp;
	struct pvr2_ctrl *cptr;
	unsigned int cnt,acnt;
512
	int ret;
513

514
	if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
515 516 517 518 519 520 521
		return;
	}

	fp = funcs + ctl_id;
	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
	if (!cptr) return;

522
	cip = kzalloc(sizeof(*cip),GFP_KERNEL);
523 524 525 526 527 528
	if (!cip) return;
	pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);

	cip->cptr = cptr;

	cip->chptr = sfp;
529
	cip->item_next = NULL;
530 531 532 533 534 535 536 537 538 539 540
	if (sfp->item_last) {
		sfp->item_last->item_next = cip;
	} else {
		sfp->item_first = cip;
	}
	sfp->item_last = cip;

	cip->attr_name.attr.name = "name";
	cip->attr_name.attr.mode = S_IRUGO;
	cip->attr_name.show = fp->show_name;

541 542 543 544
	cip->attr_type.attr.name = "type";
	cip->attr_type.attr.mode = S_IRUGO;
	cip->attr_type.show = fp->show_type;

545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573
	cip->attr_min.attr.name = "min_val";
	cip->attr_min.attr.mode = S_IRUGO;
	cip->attr_min.show = fp->show_min;

	cip->attr_max.attr.name = "max_val";
	cip->attr_max.attr.mode = S_IRUGO;
	cip->attr_max.show = fp->show_max;

	cip->attr_val.attr.name = "cur_val";
	cip->attr_val.attr.mode = S_IRUGO;

	cip->attr_custom.attr.name = "custom_val";
	cip->attr_custom.attr.mode = S_IRUGO;

	cip->attr_enum.attr.name = "enum_val";
	cip->attr_enum.attr.mode = S_IRUGO;
	cip->attr_enum.show = fp->show_enum;

	cip->attr_bits.attr.name = "bit_val";
	cip->attr_bits.attr.mode = S_IRUGO;
	cip->attr_bits.show = fp->show_bits;

	if (pvr2_ctrl_is_writable(cptr)) {
		cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
		cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
	}

	acnt = 0;
	cip->attr_gen[acnt++] = &cip->attr_name.attr;
574
	cip->attr_gen[acnt++] = &cip->attr_type.attr;
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
	cip->attr_gen[acnt++] = &cip->attr_val.attr;
	cip->attr_val.show = fp->show_val_norm;
	cip->attr_val.store = fp->store_val_norm;
	if (pvr2_ctrl_has_custom_symbols(cptr)) {
		cip->attr_gen[acnt++] = &cip->attr_custom.attr;
		cip->attr_custom.show = fp->show_val_custom;
		cip->attr_custom.store = fp->store_val_custom;
	}
	switch (pvr2_ctrl_get_type(cptr)) {
	case pvr2_ctl_enum:
		// Control is an enumeration
		cip->attr_gen[acnt++] = &cip->attr_enum.attr;
		break;
	case pvr2_ctl_int:
		// Control is an integer
		cip->attr_gen[acnt++] = &cip->attr_min.attr;
		cip->attr_gen[acnt++] = &cip->attr_max.attr;
		break;
	case pvr2_ctl_bitmask:
		// Control is an bitmask
		cip->attr_gen[acnt++] = &cip->attr_bits.attr;
		break;
	default: break;
	}

	cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
			pvr2_ctrl_get_name(cptr));
	cip->name[cnt] = 0;
	cip->grp.name = cip->name;
	cip->grp.attrs = cip->attr_gen;

606 607 608 609 610 611 612
	ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
	if (ret) {
		printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
		       __FUNCTION__, ret);
		return;
	}
	cip->created_ok = !0;
613 614 615
}

#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
616 617 618 619 620 621
static ssize_t debuginfo_show(struct device *, struct device_attribute *,
			      char *);
static ssize_t debugcmd_show(struct device *, struct device_attribute *,
			     char *);
static ssize_t debugcmd_store(struct device *, struct device_attribute *,
			      const char *, size_t count);
622 623 624 625

static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
{
	struct pvr2_sysfs_debugifc *dip;
626 627
	int ret;

628
	dip = kzalloc(sizeof(*dip),GFP_KERNEL);
629 630 631 632 633 634 635 636 637
	if (!dip) return;
	dip->attr_debugcmd.attr.name = "debugcmd";
	dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
	dip->attr_debugcmd.show = debugcmd_show;
	dip->attr_debugcmd.store = debugcmd_store;
	dip->attr_debuginfo.attr.name = "debuginfo";
	dip->attr_debuginfo.attr.mode = S_IRUGO;
	dip->attr_debuginfo.show = debuginfo_show;
	sfp->debugifc = dip;
638
	ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
639
	if (ret < 0) {
640
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
641
		       __FUNCTION__, ret);
642 643 644
	} else {
		dip->debugcmd_created_ok = !0;
	}
645
	ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
646
	if (ret < 0) {
647
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
648
		       __FUNCTION__, ret);
649 650 651
	} else {
		dip->debuginfo_created_ok = !0;
	}
652 653 654 655 656 657
}


static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
{
	if (!sfp->debugifc) return;
658
	if (sfp->debugifc->debuginfo_created_ok) {
659
		device_remove_file(sfp->class_dev,
660 661 662
					 &sfp->debugifc->attr_debuginfo);
	}
	if (sfp->debugifc->debugcmd_created_ok) {
663
		device_remove_file(sfp->class_dev,
664 665
					 &sfp->debugifc->attr_debugcmd);
	}
666
	kfree(sfp->debugifc);
667
	sfp->debugifc = NULL;
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
}
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */


static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
{
	unsigned int idx,cnt;
	cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
	for (idx = 0; idx < cnt; idx++) {
		pvr2_sysfs_add_control(sfp,idx);
	}
}


static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
{
	struct pvr2_sysfs_ctl_item *cip1,*cip2;
	for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
		cip2 = cip1->item_next;
687 688 689
		if (cip1->created_ok) {
			sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
		}
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
		pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
		kfree(cip1);
	}
}


static void pvr2_sysfs_class_release(struct class *class)
{
	struct pvr2_sysfs_class *clp;
	clp = container_of(class,struct pvr2_sysfs_class,class);
	pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp);
	kfree(clp);
}


705
static void pvr2_sysfs_release(struct device *class_dev)
706 707 708 709 710 711 712 713 714 715 716 717 718
{
	pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
	kfree(class_dev);
}


static void class_dev_destroy(struct pvr2_sysfs *sfp)
{
	if (!sfp->class_dev) return;
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
	pvr2_sysfs_tear_down_debugifc(sfp);
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
	pvr2_sysfs_tear_down_controls(sfp);
719 720 721 722 723 724 725 726
	if (sfp->hdw_desc_created_ok) {
		device_remove_file(sfp->class_dev,
				   &sfp->attr_hdw_desc);
	}
	if (sfp->hdw_name_created_ok) {
		device_remove_file(sfp->class_dev,
				   &sfp->attr_hdw_name);
	}
727
	if (sfp->bus_info_created_ok) {
728
		device_remove_file(sfp->class_dev,
729 730
					 &sfp->attr_bus_info);
	}
731
	if (sfp->v4l_minor_number_created_ok) {
732
		device_remove_file(sfp->class_dev,
733 734
					 &sfp->attr_v4l_minor_number);
	}
735
	if (sfp->v4l_radio_minor_number_created_ok) {
736
		device_remove_file(sfp->class_dev,
737 738
					 &sfp->attr_v4l_radio_minor_number);
	}
739
	if (sfp->unit_number_created_ok) {
740
		device_remove_file(sfp->class_dev,
741 742
					 &sfp->attr_unit_number);
	}
743
	pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
744 745
	sfp->class_dev->driver_data = NULL;
	device_unregister(sfp->class_dev);
746
	sfp->class_dev = NULL;
747 748 749
}


750 751
static ssize_t v4l_minor_number_show(struct device *class_dev,
				     struct device_attribute *attr, char *buf)
752 753
{
	struct pvr2_sysfs *sfp;
754
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
755 756
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%d\n",
757
			 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
758
						       pvr2_v4l_type_video));
759 760 761
}


762 763
static ssize_t bus_info_show(struct device *class_dev,
			     struct device_attribute *attr, char *buf)
764 765
{
	struct pvr2_sysfs *sfp;
766
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
767 768 769 770 771 772
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%s\n",
			 pvr2_hdw_get_bus_info(sfp->channel.hdw));
}


773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
static ssize_t hdw_name_show(struct device *class_dev,
			     struct device_attribute *attr, char *buf)
{
	struct pvr2_sysfs *sfp;
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%s\n",
			 pvr2_hdw_get_type(sfp->channel.hdw));
}


static ssize_t hdw_desc_show(struct device *class_dev,
			     struct device_attribute *attr, char *buf)
{
	struct pvr2_sysfs *sfp;
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%s\n",
			 pvr2_hdw_get_desc(sfp->channel.hdw));
}


795 796
static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
					   struct device_attribute *attr,
797 798 799
					   char *buf)
{
	struct pvr2_sysfs *sfp;
800
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
801 802
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%d\n",
803
			 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
804
						       pvr2_v4l_type_radio));
805 806 807
}


808 809
static ssize_t unit_number_show(struct device *class_dev,
				struct device_attribute *attr, char *buf)
810 811
{
	struct pvr2_sysfs *sfp;
812
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
813 814 815 816 817 818 819 820 821 822
	if (!sfp) return -EINVAL;
	return scnprintf(buf,PAGE_SIZE,"%d\n",
			 pvr2_hdw_get_unit_number(sfp->channel.hdw));
}


static void class_dev_create(struct pvr2_sysfs *sfp,
			     struct pvr2_sysfs_class *class_ptr)
{
	struct usb_device *usb_dev;
823
	struct device *class_dev;
824 825
	int ret;

826 827
	usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
	if (!usb_dev) return;
828
	class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
829 830 831 832 833 834
	if (!class_dev) return;

	pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);

	class_dev->class = &class_ptr->class;
	if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
835
		snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu",
836 837
			 pvr2_hdw_get_sn(sfp->channel.hdw));
	} else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
838
		snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c",
839 840 841 842 843 844
			 pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
	} else {
		kfree(class_dev);
		return;
	}

845
	class_dev->parent = &usb_dev->dev;
846 847

	sfp->class_dev = class_dev;
848 849
	class_dev->driver_data = sfp;
	ret = device_register(class_dev);
850
	if (ret) {
851
		printk(KERN_ERR "%s: device_register failed\n",
852 853 854 855
		       __FUNCTION__);
		kfree(class_dev);
		return;
	}
856 857 858 859

	sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
	sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
	sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
860
	sfp->attr_v4l_minor_number.store = NULL;
861
	ret = device_create_file(sfp->class_dev,
862 863
				       &sfp->attr_v4l_minor_number);
	if (ret < 0) {
864
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
865
		       __FUNCTION__, ret);
866 867 868
	} else {
		sfp->v4l_minor_number_created_ok = !0;
	}
869

870 871 872 873
	sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
	sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
	sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
	sfp->attr_v4l_radio_minor_number.store = NULL;
874
	ret = device_create_file(sfp->class_dev,
875 876
				       &sfp->attr_v4l_radio_minor_number);
	if (ret < 0) {
877
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
878 879 880 881 882
		       __FUNCTION__, ret);
	} else {
		sfp->v4l_radio_minor_number_created_ok = !0;
	}

883 884 885
	sfp->attr_unit_number.attr.name = "unit_number";
	sfp->attr_unit_number.attr.mode = S_IRUGO;
	sfp->attr_unit_number.show = unit_number_show;
886
	sfp->attr_unit_number.store = NULL;
887
	ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
888
	if (ret < 0) {
889
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
890
		       __FUNCTION__, ret);
891 892 893
	} else {
		sfp->unit_number_created_ok = !0;
	}
894

895 896 897 898
	sfp->attr_bus_info.attr.name = "bus_info_str";
	sfp->attr_bus_info.attr.mode = S_IRUGO;
	sfp->attr_bus_info.show = bus_info_show;
	sfp->attr_bus_info.store = NULL;
899
	ret = device_create_file(sfp->class_dev,
900 901
				       &sfp->attr_bus_info);
	if (ret < 0) {
902
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
903 904 905 906 907
		       __FUNCTION__, ret);
	} else {
		sfp->bus_info_created_ok = !0;
	}

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
	sfp->attr_hdw_name.attr.name = "device_hardware_type";
	sfp->attr_hdw_name.attr.mode = S_IRUGO;
	sfp->attr_hdw_name.show = hdw_name_show;
	sfp->attr_hdw_name.store = NULL;
	ret = device_create_file(sfp->class_dev,
				 &sfp->attr_hdw_name);
	if (ret < 0) {
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
		       __FUNCTION__, ret);
	} else {
		sfp->hdw_name_created_ok = !0;
	}

	sfp->attr_hdw_desc.attr.name = "device_hardware_description";
	sfp->attr_hdw_desc.attr.mode = S_IRUGO;
	sfp->attr_hdw_desc.show = hdw_desc_show;
	sfp->attr_hdw_desc.store = NULL;
	ret = device_create_file(sfp->class_dev,
				 &sfp->attr_hdw_desc);
	if (ret < 0) {
		printk(KERN_WARNING "%s: device_create_file error: %d\n",
		       __FUNCTION__, ret);
	} else {
		sfp->hdw_desc_created_ok = !0;
	}

934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
	pvr2_sysfs_add_controls(sfp);
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
	pvr2_sysfs_add_debugifc(sfp);
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
}


static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)
{
	struct pvr2_sysfs *sfp;
	sfp = container_of(chp,struct pvr2_sysfs,channel);
	if (!sfp->channel.mc_head->disconnect_flag) return;
	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);
	class_dev_destroy(sfp);
	pvr2_channel_done(&sfp->channel);
	kfree(sfp);
}


struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
				     struct pvr2_sysfs_class *class_ptr)
{
	struct pvr2_sysfs *sfp;
957
	sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
958 959 960 961 962 963 964 965 966 967 968 969 970 971
	if (!sfp) return sfp;
	pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
	pvr2_channel_init(&sfp->channel,mp);
	sfp->channel.check_func = pvr2_sysfs_internal_check;

	class_dev_create(sfp,class_ptr);
	return sfp;
}



struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
	struct pvr2_sysfs_class *clp;
972
	clp = kzalloc(sizeof(*clp),GFP_KERNEL);
973 974 975 976
	if (!clp) return clp;
	pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
	clp->class.name = "pvrusb2";
	clp->class.class_release = pvr2_sysfs_class_release;
977
	clp->class.dev_release = pvr2_sysfs_release;
978 979 980 981
	if (class_register(&clp->class)) {
		pvr2_sysfs_trace(
			"Registration failed for pvr2_sysfs_class id=%p",clp);
		kfree(clp);
982
		clp = NULL;
983 984 985 986 987 988 989 990 991 992 993 994
	}
	return clp;
}


void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
{
	class_unregister(&clp->class);
}


#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
995 996
static ssize_t debuginfo_show(struct device *class_dev,
			      struct device_attribute *attr, char *buf)
997 998
{
	struct pvr2_sysfs *sfp;
999
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
1000 1001 1002 1003 1004 1005
	if (!sfp) return -EINVAL;
	pvr2_hdw_trigger_module_log(sfp->channel.hdw);
	return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
}


1006 1007
static ssize_t debugcmd_show(struct device *class_dev,
			     struct device_attribute *attr, char *buf)
1008 1009
{
	struct pvr2_sysfs *sfp;
1010
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
1011 1012 1013 1014 1015
	if (!sfp) return -EINVAL;
	return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
}


1016
static ssize_t debugcmd_store(struct device *class_dev,
1017
			      struct device_attribute *attr,
1018
			      const char *buf, size_t count)
1019 1020 1021 1022
{
	struct pvr2_sysfs *sfp;
	int ret;

1023
	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
	if (!sfp) return -EINVAL;

	ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
	if (ret < 0) return ret;
	return count;
}
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */


/*
  Stuff for Emacs to see, in order to encourage consistent editing style:
  *** Local Variables: ***
  *** mode: c ***
  *** fill-column: 75 ***
  *** tab-width: 8 ***
  *** c-basic-offset: 8 ***
  *** End: ***
  */