~ubuntu-branches/ubuntu/precise/qc-usb/precise

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
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
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
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
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
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
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
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
574
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
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
/* Start of file */

/* {{{ [fold] Comments */
/*
 * qc-usb, linux V4L driver for the Logitech QuickCam USB camera family
 *
 * qc-hdcs.c - HDCS Sensor Implementation
 *
 * 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, or
 * (at your option) any later version.
 *
 * 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
 *
 */
/* }}} */

#ifdef NOKERNEL
#include "quickcam.h"
#else
#include <linux/quickcam.h>
#endif

/* LSB bit of I2C or register address signifies write (0) or read (1) */

/* I2C Address */
#define HDCS_ADDR 	(0x55<<1)
 
/* {{{ [fold] I2C registers */
/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */
#define HDCS_IDENT	(0x00<<1)	/* Identifications Register */
#define HDCS_STATUS	(0x01<<1)	/* Status Register */
#define HDCS_IMASK	(0x02<<1)	/* Interrupt Mask Register */
#define HDCS_PCTRL	(0x03<<1)	/* Pad Control Register */
#define HDCS_PDRV	(0x04<<1)	/* Pad Drive Control Register */
#define HDCS_ICTRL	(0x05<<1)	/* Interface Control Register */
#define HDCS_ITMG	(0x06<<1)	/* Interface Timing Register */
#define HDCS_BFRAC	(0x07<<1)	/* Baud Fraction Register */
#define HDCS_BRATE	(0x08<<1)	/* Baud Rate Register */
#define HDCS_ADCCTRL	(0x09<<1)	/* ADC Control Register */
#define HDCS_FWROW	(0x0A<<1)	/* First Window Row Register */
#define HDCS_FWCOL	(0x0B<<1)	/* First Window Column Register */
#define HDCS_LWROW	(0x0C<<1)	/* Last Window Row Register */
#define HDCS_LWCOL	(0x0D<<1)	/* Last Window Column Register */
#define HDCS_TCTRL	(0x0E<<1)	/* Timing Control Register */
#define HDCS_ERECPGA	(0x0F<<1)	/* PGA Gain Register: Even Row, Even Column */
#define HDCS_EROCPGA	(0x10<<1)	/* PGA Gain Register: Even Row, Odd Column */
#define HDCS_ORECPGA	(0x11<<1)	/* PGA Gain Register: Odd Row, Even Column */
#define HDCS_OROCPGA	(0x12<<1)	/* PGA Gain Register: Odd Row, Odd Column */
#define HDCS_ROWEXPL	(0x13<<1)	/* Row Exposure Low Register */
#define HDCS_ROWEXPH	(0x14<<1)	/* Row Exposure High Register */

/* I2C Registers only for HDCS-1000/1100 */
#define HDCS00_SROWEXPL	(0x15<<1)	/* Sub-Row Exposure Low Register */
#define HDCS00_SROWEXPH	(0x16<<1)	/* Sub-Row Exposure High Register */
#define HDCS00_CONFIG	(0x17<<1)	/* Configuration Register */
#define HDCS00_CONTROL	(0x18<<1)	/* Control Register */

/* I2C Registers only for HDCS-1020 */
#define HDCS20_SROWEXP	(0x15<<1)	/* Sub-Row Exposure Register	*/
#define HDCS20_ERROR	(0x16<<1)	/* Error Control Register 	*/
#define HDCS20_ITMG2	(0x17<<1)	/* Interface Timing 2 Register	*/
#define HDCS20_ICTRL2	(0x18<<1)	/* Interface Control 2 Register	*/
#define HDCS20_HBLANK	(0x19<<1)	/* Horizontal Blank Register	*/
#define HDCS20_VBLANK	(0x1A<<1)	/* Vertical Blank Register	*/
#define HDCS20_CONFIG	(0x1B<<1)	/* Configuration Register 	*/
#define HDCS20_CONTROL	(0x1C<<1)	/* Control Register		*/
/* }}} */

#define IS_870(qc)	(GET_PRODUCTID(qc)==0x870)
#define IS_1020(qc)	((qc)->sensor_data.sensor->flag != 0)
#define GET_CONTROL	(IS_1020(qc) ? HDCS20_CONTROL : HDCS00_CONTROL)
#define GET_CONFIG	(IS_1020(qc) ? HDCS20_CONFIG : HDCS00_CONFIG)

#define I2C_SET_CHECK(reg,val)	if ((r = qc_i2c_set(qc,(reg),(val)))<0) goto fail
#define STV_SET_CHECK(reg,val)	if ((r = qc_stv_set(qc,(reg),(val)))<0) goto fail
#define STV_SETW_CHECK(reg,val)	if ((r = qc_stv_setw(qc,(reg),(val)))<0) goto fail

/* Enables experimental compressed mode, works with HDCS-1000/0x840,
   mode derived from USB logs obtained from HDCS-1020/0x870
   (should give 640x480), not tested with HDCS-1020.
   On HDCS-1000, gives 30 fps but data is in unknown format,
   observed image width 163 bytes (how many pixels?).
   Frame length appears to vary, typically 3300-4550 bytes.
   (apparently quite simple, however).
    Use this with DUMPDATA mode. */
#define HDCS_COMPRESS 0

#if HDCS_COMPRESS
/* {{{ [fold] hdcs_compress_init(struct quickcam *qc, int flags) */
static int hdcs_compress_init(struct quickcam *qc, int flags)
{
	int r;

	if (flags & 1) {
	/************************************** Plugin camera **************************************/

	STV_SET_CHECK(0x1440, 0x00);							/* Turn on/off isochronous stream */
	// if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870)					/* ProductId */
	//	PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r);

	STV_SET_CHECK(0x0423, 0x05);							/* Unknown (sometimes 4, sometimes 5) */
	// Warning: I2C address 0xBA is invalid
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x0a)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r);
	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */

	if ((r = qc_stv_get(qc, 0x1444)) != 0x10)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r);
	if ((r = qc_stv_get(qc, 0x1444)) != 0x10)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r);
	if ((r = qc_stv_get(qc, 0x1444)) != 0x10)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1444, should be 0x10", r);

	STV_SET_CHECK(0x0423, 0x05);							/* Unknown (sometimes 4, sometimes 5) */
	// Warning: I2C address 0x20 is invalid
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x0a)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r);
	// Warning: I2C address 0x20 is invalid
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x0a)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r);
	// Warning: I2C address 0x20 is invalid
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x0a)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x0a", r);
	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */
	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */

	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x02)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r);
	// if ((r = qc_stv_get(qc, 0x1410)) != 0x10)					/* I2C area, first reg value */
	//	PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r);

	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x02)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r);
	// if ((r = qc_stv_get(qc, 0x1410)) != 0x10)					/* I2C area, first reg value */
	//	PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r);

	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */
	if ((r = qc_stv_get(qc, 0x0424)) != 0x02)					/* Successfully transmitted I2C commands */
		PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r);
	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */

	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x02)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r);
	// if ((r = qc_stv_get(qc, 0x1410)) != 0x10)					/* I2C area, first reg value */
	//	PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r);

	// if ((r = qc_get_i2c(qc, qc->sensor_data.sensor, HDCS_IDENT))<0)		/* Identifications Register */
	//	PDEBUG("error reading sensor reg HDCS_IDENT");
	// if ((r = qc_stv_get(qc, 0x0424)) != 0x02)					/* Successfully transmitted I2C commands */
	//	PDEBUG("Bad value 0x%02X in reg 0x0424, should be 0x02", r);
	// if ((r = qc_stv_get(qc, 0x1410)) != 0x10)					/* I2C area, first reg value */
	//	PDEBUG("Bad value 0x%02X in reg 0x1410, should be 0x10", r);

	STV_SET_CHECK(0x1500, 0x1D);							/* ? */
	if ((r = qc_stv_get(qc, 0x1443)) != 0x00)					/* Scan rate? */
		PDEBUG("Bad value 0x%02X in reg 0x1443, should be 0x00", r);
	STV_SET_CHECK(0x1443, 0x01);							/* Scan rate? */
	if ((r = qc_stv_get(qc, 0x1443)) != 0x01)					/* Scan rate? */
		PDEBUG("Bad value 0x%02X in reg 0x1443, should be 0x01", r);
	STV_SET_CHECK(0x1443, 0x00);							/* Scan rate? */

	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	I2C_SET_CHECK(GET_CONTROL, 0x04);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	I2C_SET_CHECK(GET_CONTROL, 0x00);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);
	I2C_SET_CHECK(HDCS_ERECPGA, 0x3B);						/* PGA Gain Register: Even Row, Even Column */
	I2C_SET_CHECK(HDCS_EROCPGA, 0x3B);						/* PGA Gain Register: Even Row, Odd Column */
	I2C_SET_CHECK(HDCS_ORECPGA, 0x3B);						/* PGA Gain Register: Odd Row, Even Column */
	I2C_SET_CHECK(HDCS_OROCPGA, 0x3B);						/* PGA Gain Register: Odd Row, Odd Column */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1504, 0x07);							/* ? */
	STV_SET_CHECK(0x1503, 0x45);							/* ? */
	if ((r = qc_stv_get(qc, 0x1500)) != 0x1d)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1500, should be 0x1d", r);
	STV_SET_CHECK(0x1500, 0x1D);							/* ? */
	// if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870)					/* ProductId */
	//	PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r);
	}
	
	if (flags & 2) {
	/************************************** Start grabbing **************************************/

	// if ((r = qc_stv_getw(qc, 0xE00A)) != 0x0870)					/* ProductId */
	//	PDEBUG("Bad value 0x%02X in reg 0xE00A, should be 0x0870", r);
	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */
	STV_SET_CHECK(0x1500, 0x1D);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x15C3, 0x02);							/* Y-Control, 1: 288 lines, 2: 144 lines */
	STV_SETW_CHECK(0x15C1, 0x027B);							/* Max. ISO packet size */
	I2C_SET_CHECK(HDCS_FWROW, 0x00);						/* First Window Row Register */
	I2C_SET_CHECK(HDCS_FWCOL, 0x0B);						/* First Window Column Register */
	I2C_SET_CHECK(HDCS_LWROW, 0x3D);						/* Last Window Row Register */
	I2C_SET_CHECK(HDCS_LWCOL, 0x5A);						/* Last Window Column Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1680, 0x00);							/* X-Control, 0xa: 352 columns, 6: 176 columns */
	I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCB : 0x6B);				/* Timing Control Register */
	I2C_SET_CHECK(HDCS_ICTRL, 0x00);						/* Interface Control Register */
	I2C_SET_CHECK(HDCS_ITMG, 0x16);							/* Interface Timing Register */
	if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xD6);				/* Horizontal Blank Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	if ((r = qc_stv_get(qc, 0x1446)) != 0x00)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r);
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	I2C_SET_CHECK(HDCS_ROWEXPL, 0x7B);						/* Row Exposure Low Register */
	I2C_SET_CHECK(HDCS_ROWEXPH, 0x00);						/* Row Exposure High Register */
	if (IS_1020(qc)) {
		I2C_SET_CHECK(HDCS20_SROWEXP, 0x01);					/* Sub-Row Exposure Register */
	} else {
		I2C_SET_CHECK(HDCS00_SROWEXPL, 0x01<<2);
		I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00);
	}
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1501, 0xC2);							/* ? */
	STV_SET_CHECK(0x1502, 0xB0);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	/* Start isochronous streaming */
	I2C_SET_CHECK(GET_CONTROL, 0x04);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1440, 0x01);							/* Turn on/off isochronous stream */

	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);
	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);
	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);

	/* Stop isochronous streaming */
	STV_SET_CHECK(0x1440, 0x00);							/* Turn on/off isochronous stream */
	I2C_SET_CHECK(GET_CONTROL, 0x00);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */
	STV_SET_CHECK(0x1500, 0x1D);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x15C3, 0x02);							/* Y-Control, 1: 288 lines, 2: 144 lines */
	STV_SETW_CHECK(0x15C1, 0x027B);							/* Max. ISO packet size */
	I2C_SET_CHECK(HDCS_FWROW, 0x00);						/* First Window Row Register */
	I2C_SET_CHECK(HDCS_FWCOL, 0x0B);						/* First Window Column Register */
	I2C_SET_CHECK(HDCS_LWROW, 0x3D);						/* Last Window Row Register */
	I2C_SET_CHECK(HDCS_LWCOL, 0x5A);						/* Last Window Column Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1680, 0x00);							/* X-Control, 0xa: 352 columns, 6: 176 columns */
	I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCB : 0x6B);				/* Timing Control Register */
	I2C_SET_CHECK(HDCS_ICTRL, 0x00);						/* Interface Control Register */
	I2C_SET_CHECK(HDCS_ITMG, 0x16);							/* Interface Timing Register */
	if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xD6);				/* Horizontal Blank Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	if ((r = qc_stv_get(qc, 0x1446)) != 0x00)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r);
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	I2C_SET_CHECK(HDCS_ROWEXPL, 0x7B);						/* Row Exposure Low Register */
	I2C_SET_CHECK(HDCS_ROWEXPH, 0x00);						/* Row Exposure High Register */
	if (IS_1020(qc)) {
		I2C_SET_CHECK(HDCS20_SROWEXP, 0x01);					/* Sub-Row Exposure Register */
	} else {
		I2C_SET_CHECK(HDCS00_SROWEXPL, 0x01<<2);
		I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00);
	}
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1501, 0xC2);							/* ? */
	STV_SET_CHECK(0x1502, 0xB0);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	/* Start isochronous streaming */
	I2C_SET_CHECK(GET_CONTROL, 0x04);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);
	STV_SET_CHECK(0x1440, 0x01);							/* Turn on/off isochronous stream */

	/* Stop isochronous streaming */
	STV_SET_CHECK(0x1440, 0x00);							/* Turn on/off isochronous stream */
	I2C_SET_CHECK(GET_CONTROL, 0x00);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	STV_SET_CHECK(0x0423, 0x04);							/* Unknown (sometimes 4, sometimes 5) */
	STV_SET_CHECK(0x1500, 0x1D);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x15C3, 0x02);							/* Y-Control, 1: 288 lines, 2: 144 lines */
	STV_SETW_CHECK(0x15C1, 0x0230);							/* Max. ISO packet size */
	I2C_SET_CHECK(HDCS_FWROW, 0x00);						/* First Window Row Register */
	I2C_SET_CHECK(HDCS_FWCOL, 0x07);						/* First Window Column Register */
	I2C_SET_CHECK(HDCS_LWROW, 0x49);						/* Last Window Row Register */
	I2C_SET_CHECK(HDCS_LWCOL, 0x5E);						/* Last Window Column Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1680, 0x00);							/* X-Control, 0xa: 352 columns, 6: 176 columns */
	I2C_SET_CHECK(HDCS_TCTRL, IS_1020(qc) ? 0xCE : 0x6E);				/* Timing Control Register */
	I2C_SET_CHECK(HDCS_ICTRL, 0x00);						/* Interface Control Register */
	I2C_SET_CHECK(HDCS_ITMG, 0x16);							/* Interface Timing Register */
	if (IS_1020(qc)) I2C_SET_CHECK(HDCS20_HBLANK, 0xCF);				/* Horizontal Blank Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	if ((r = qc_stv_get(qc, 0x1446)) != 0x00)					/* ? */
		PDEBUG("Bad value 0x%02X in reg 0x1446, should be 0x00", r);
	STV_SET_CHECK(0x1446, 0x00);							/* ? */
	I2C_SET_CHECK(HDCS_ROWEXPL, 0x62);						/* Row Exposure Low Register */
	I2C_SET_CHECK(HDCS_ROWEXPH, 0x00);						/* Row Exposure High Register */
	if (IS_1020(qc)) {
		I2C_SET_CHECK(HDCS20_SROWEXP, 0x1A);					/* Sub-Row Exposure Register */
	} else {
		I2C_SET_CHECK(HDCS00_SROWEXPL, 0x1A<<2);
		I2C_SET_CHECK(HDCS00_SROWEXPH, 0x00);
	}
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1501, 0xB6);							/* ? */
	STV_SET_CHECK(0x1502, 0xA8);							/* ? */
	I2C_SET_CHECK(HDCS_PCTRL, 0x63);						/* Pad Control Register */
	I2C_SET_CHECK(HDCS_PDRV, 0x00);							/* Pad Drive Control Register */
	I2C_SET_CHECK(GET_CONFIG, 0x08);						/* Configuration Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	/* Start isochronous streaming */
	I2C_SET_CHECK(GET_CONTROL, 0x04);						/* Control Register */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	STV_SET_CHECK(0x1440, 0x01);							/* Turn on/off isochronous stream */

	if ((r = qc_stv_get(qc, 0x1445)) != 0x04)					/* Turn LED on/off? */
		PDEBUG("Bad value 0x%02X in reg 0x1445, should be 0x04", r);
	}

	return 0;
fail:	return r;
}
/* }}} */
#endif
/* {{{ [fold] hdcs_init: Initialise parameters (from Georg Acher's user module for hdcs sensor) */
static int hdcs_init(struct quickcam *qc)
{
	struct qc_sensor_data *sd = &qc->sensor_data;
	unsigned char control = GET_CONTROL;
	unsigned char config = GET_CONFIG;
	int r,tctrl,astrt,psmp;

	if (sd->compress) return -EINVAL;
	sd->maxwidth  = IS_1020(qc) ? 352 : 360;	/* CIF */
	sd->maxheight = IS_1020(qc) ? 292 : 296;
	if (sd->subsample) {
		sd->maxwidth  /= 2;		/* QCIF */
		sd->maxheight /= 2;
	}
	if ((r = qc_i2c_break(qc))<0) goto fail;	/* The following setting must go into same I2C packet */
#if HDCS_COMPRESS
r = hdcs_compress_init(qc, 3);
qc_i2c_wait(qc);
qc_i2c_break(qc);
qc_stv_set(qc, 0x1440, 0x00);		/* Turn on/off isochronous stream */
qc_i2c_set(qc, GET_CONTROL, BIT(1));	/* Stop and enter sleep mode */
qc_i2c_wait(qc);
if (r) PDEBUG("hdcs_compress_init(1) = %i", r);
return 0;
#endif
	STV_SET_CHECK(STV_REG23, 0);

	/* Set the STV0602AA in STV0600 emulation mode */
	if (IS_870(qc)) STV_SET_CHECK(0x1446, 1);

	/* Reset the image sensor (keeping it to 1 is a problem) */
	I2C_SET_CHECK(control, 1);
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	I2C_SET_CHECK(control, 0);
	if ((r = qc_i2c_wait(qc))<0) goto fail;
	
	I2C_SET_CHECK(HDCS_STATUS, BIT(6)|BIT(5)|BIT(4)|BIT(3)|BIT(2)|BIT(1));	/* Clear status (writing 1 will clear the corresponding status bit) */
	
	I2C_SET_CHECK(HDCS_IMASK, 0x00);	/* Disable all interrupts */
	if ((r = qc_i2c_wait(qc))<0) goto fail;

	STV_SET_CHECK(STV_REG00, 0x1D);
	STV_SET_CHECK(STV_REG04, 0x07);
	STV_SET_CHECK(STV_REG03, 0x95);

	STV_SET_CHECK(STV_REG23, 0);

	STV_SET_CHECK(STV_SCAN_RATE, 0x20);	/* Larger -> slower */

	STV_SETW_CHECK(STV_ISO_SIZE, 847);	/* ISO-Size, 0x34F = 847 .. 0x284 = 644 */

	/* Set mode */
	STV_SET_CHECK(STV_Y_CTRL, 0x01);	/* 0x02: half, 0x01: full */
	STV_SET_CHECK(STV_X_CTRL, 0x0A);	/* 0x06: half, 0x0A: full */
 
	/* These are not good final values, which will be set in set_size */
	/* However, it looks like it's best to set some values at this point nevertheless */
	I2C_SET_CHECK(HDCS_FWROW, 0);		/* Start at row 0 */
	I2C_SET_CHECK(HDCS_FWCOL, 0);		/* Start at column 0 */
	I2C_SET_CHECK(HDCS_LWROW, 0x47);	/* End at row 288 */
	I2C_SET_CHECK(HDCS_LWCOL, 0x57);	/* End at column 352 */

	/* 0x07 - 0x50 */
	astrt = 3;	/* 0..3, doesn't seem to have any effect... hmm.. smaller is slower with subsampling */
	if (!IS_1020(qc)) {
		/* HDCS-1000 (tctrl was 0x09, but caused some HDCS-1000 not to work) */
		/* Frame rate on HDCS-1000 0x46D:0x840 depending on PSMP:
		 *  4 = doesn't work at all
		 *  5 = 7.8 fps,
		 *  6 = 6.9 fps,
		 *  8 = 6.3 fps,
		 * 10 = 5.5 fps,
		 * 15 = 4.4 fps,
		 * 31 = 2.8 fps */
		/* Frame rate on HDCS-1000 0x46D:0x870 depending on PSMP:
		 * 15 = doesn't work at all
		 * 18 = doesn't work at all
		 * 19 = 7.3 fps
		 * 20 = 7.4 fps
		 * 21 = 7.4 fps
		 * 22 = 7.4 fps
		 * 24 = 6.3 fps
		 * 30 = 5.4 fps */
		psmp = IS_870(qc) ? 20 : 5;	/* 4..31 (was 30, changed to 20) */
		tctrl = (astrt<<5) | psmp;
	} else {
		/* HDCS-1020 (tctrl was 0x7E, but causes slow frame rate on HDCS-1020) */
		/* Changed to 6 which should give 8.1 fps */
		psmp = 6;			/* 4..31 (was 9, changed to 6 to improve fps */
		tctrl = (astrt<<6) | psmp;
	}
	I2C_SET_CHECK(HDCS_TCTRL, tctrl);	/* Set PGA sample duration (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */

	I2C_SET_CHECK(control, 0);		/* FIXME:should not be anymore necessary (already done) */

	I2C_SET_CHECK(HDCS_ROWEXPL, 0);
	I2C_SET_CHECK(HDCS_ROWEXPH, 0);
	if (IS_1020(qc)) {
		I2C_SET_CHECK(HDCS20_SROWEXP, 0);
		I2C_SET_CHECK(HDCS20_ERROR, BIT(0)|BIT(2));	/* Clear error conditions by writing 1 */
	} else {
		I2C_SET_CHECK(HDCS00_SROWEXPL, 0);
		I2C_SET_CHECK(HDCS00_SROWEXPH, 0);
	}
	if ((r = qc_i2c_wait(qc))<0) goto fail;
 
	STV_SET_CHECK(STV_REG01, 0xB5);
	STV_SET_CHECK(STV_REG02, 0xA8);

	I2C_SET_CHECK(HDCS_PCTRL, BIT(6)|BIT(5)|BIT(1)|BIT(0));
	I2C_SET_CHECK(HDCS_PDRV,  0x00);
	I2C_SET_CHECK(HDCS_ICTRL, (sd->subsample ? BIT(7) : 0) | BIT(5));
	I2C_SET_CHECK(HDCS_ITMG,  BIT(4)|BIT(1));

	/* CONFIG: Bit 3: continous frame capture, bit 2: stop when frame complete */
	I2C_SET_CHECK(config, (sd->subsample ? BIT(5) : 0) | BIT(3));
	I2C_SET_CHECK(HDCS_ADCCTRL, 10);	/* ADC output resolution to 10 bits */
	if ((r = qc_i2c_wait(qc))<0) goto fail;
fail:	return r;
}
/* }}} */
/* {{{ [fold] hdcs_start: Start grabbing */
static int hdcs_start(struct quickcam *qc)
{
	int r;
#if HDCS_COMPRESS
r = hdcs_compress_init(qc, 2);
qc_i2c_wait(qc);
if (r) PDEBUG("hdcs_compress_init(1) = %i", r);
return 0;
#endif
	if ((r = qc_i2c_break(qc))<0) goto fail;
	I2C_SET_CHECK(GET_CONTROL, BIT(2));	/* Run enable */
	if ((r = qc_i2c_break(qc))<0) goto fail;
fail:	return r;
}
/* }}} */
/* {{{ [fold] hdcs_stop: Stop grabbing */
static int hdcs_stop(struct quickcam *qc)
{
	int r;
	if ((r = qc_i2c_break(qc))<0) goto fail;
	I2C_SET_CHECK(GET_CONTROL, BIT(1));	/* Stop and enter sleep mode */
	r = qc_i2c_wait(qc);
fail:	return r;
}
/* }}} */
/* {{{ [fold] hdcs_set_exposure: Set exposure time, val=0..65535 */
static int hdcs_set_exposure(struct quickcam *qc, unsigned int val)
{
	struct qc_sensor_data *sd = &qc->sensor_data;
	unsigned char control = GET_CONTROL;
	unsigned int rowexp;		/* rowexp,srowexp = 15 bits (0..32767) */
	unsigned int srowexp;		/* sub-row exposure (smaller is brighter) */
	unsigned int max_srowexp;	/* Maximum srowexp value + 1 */
	int r;

	/* Absolute black at srowexp=2672,width=360; 2616, width=352; 1896, width=256 for hdcs1000 */

	if (val==sd->exposure) return 0;
	sd->exposure = val;
	val *= 16;		/* 16 seems to be the smallest change that actually affects brightness */
	max_srowexp = sd->width*15/2 - 104 + 1;
	srowexp = max_srowexp - (val % max_srowexp) - 1;
	rowexp  = val / max_srowexp;
	if (qcdebug&QC_DEBUGCAMERA) PDEBUG("width=%i height=%i rowexp=%i srowexp=%i",sd->width,sd->height,rowexp,srowexp);
	if ((r = qc_i2c_break(qc))<0) goto fail;		/* The following setting must go into same I2C packet */
	I2C_SET_CHECK(control, 0);				/* Stop grabbing */
	I2C_SET_CHECK(HDCS_ROWEXPL, rowexp & 0xFF);		/* Number of rows to expose */
	I2C_SET_CHECK(HDCS_ROWEXPH, rowexp >> 8);
	if (IS_1020(qc)) {
		srowexp = 0;	//FIXME:need formula to compute srowexp for HDCS1020!
		srowexp >>= 2;					/* Bits 0..1 are hardwired to 0 */
		I2C_SET_CHECK(HDCS20_SROWEXP, srowexp & 0xFF);	/* Number of pixels to expose */
	} else {
		I2C_SET_CHECK(HDCS00_SROWEXPL, srowexp & 0xFF);	/* Number of pixels to expose */
		I2C_SET_CHECK(HDCS00_SROWEXPH, srowexp >> 8);
	}
	if (IS_1020(qc)) {
		I2C_SET_CHECK(HDCS20_ERROR, BIT(0));		/* Reset exposure error flag */
	} else {
		I2C_SET_CHECK(HDCS_STATUS, BIT(4));		/* Reset exposure error flag */
	}
	I2C_SET_CHECK(control, BIT(2));				/* Restart grabbing */
	if ((r = qc_i2c_break(qc))<0) goto fail;
#if 0
	/* Warning: the code below will cause about 0.1 second delay and may cause lost frames */
	if (PARANOID) {
		/* Check if the new exposure setting is valid */
		if ((r = qc_i2c_wait(qc))<0) goto fail;
		if (IS_1020(qc)) {
			if ((r = qc_get_i2c(qc,qc->sensor_data.sensor, HDCS20_ERROR))<0) goto fail;
			if (r & BIT(0)) PDEBUG("exposure error (1020)");
		} else {
			if ((r = qc_get_i2c(qc,qc->sensor_data.sensor, HDCS_STATUS))<0) goto fail;
			if (r & BIT(4)) PDEBUG("exposure error (1000)");
		}
	}
	if ((r = qc_i2c_wait(qc))<0) goto fail;
#endif
	qc_frame_flush(qc);
fail:	return (r<0) ? r : 0;
}
/* }}} */
/* {{{ [fold] hdcs_set_gains: Set gains */
static int hdcs_set_gains(struct quickcam *qc, unsigned int hue, unsigned int sat, unsigned int val)
{
	static const unsigned int min_gain = 8;
	struct qc_sensor_data *sd = &qc->sensor_data;
	unsigned int rgain, bgain, ggain;
	int r;
	qc_hsv2rgb(hue, sat, val, &rgain, &bgain, &ggain);
	rgain >>= 8;					/* After this the values are 0..255 */
	ggain >>= 8;
	bgain >>= 8;
	rgain = MAX(rgain, min_gain);			/* Do not allow very small values, they cause bad (low-contrast) image */
	ggain = MAX(ggain, min_gain);
	bgain = MAX(bgain, min_gain);
	if (rgain==sd->rgain && ggain==sd->ggain && bgain==sd->bgain) return 0;
	sd->rgain = rgain;			
	sd->ggain = ggain;
	sd->bgain = bgain;
	if (rgain > 127) rgain = rgain/2 | BIT(7);	/* Bit 7 doubles the programmed values */
	if (ggain > 127) ggain = ggain/2 | BIT(7);	/* Double programmed value if necessary */
	if (bgain > 127) bgain = bgain/2 | BIT(7);
	if ((r = qc_i2c_break(qc))<0) goto fail;
	I2C_SET_CHECK(HDCS_ERECPGA, ggain);
	I2C_SET_CHECK(HDCS_EROCPGA, rgain);
	I2C_SET_CHECK(HDCS_ORECPGA, bgain);
	I2C_SET_CHECK(HDCS_OROCPGA, ggain);
fail:	return r;
}
/* }}} */
/* {{{ [fold] hdcs_set_levels() */
static int hdcs_set_levels(struct quickcam *qc, unsigned int exp, unsigned int gain, unsigned int hue, unsigned int sat)
{
	int r = 0;
//#if !HDCS_COMPRESS
	if ((r = hdcs_set_exposure(qc, gain))<0) goto fail;
//#endif
	hdcs_set_gains(qc, hue, sat, exp);
fail:	return r;
}
/* }}} */
/* {{{ [fold] hdcs_set_size: Sets the size of the capture window */
/*
 *  Sets the size (scaling) of the capture window.
 *  If subsample could return the image size we use subsample.
 */
static int hdcs_set_size(struct quickcam *qc, unsigned int width, unsigned int height)
{
	/* The datasheet doesn't seem to say this, but HDCS-1000
	 * has visible windows size of 360x296 pixels, the first upper-left
	 * visible pixel is at 8,8.
	 * From Andrey's test image: looks like HDCS-1020 upper-left
	 * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
	 * visible pixel at 375,299 (x maybe even larger?)
	 */
	unsigned int originx   = IS_1020(qc) ? 24 : 8;		/* First visible pixel */
	unsigned int maxwidth  = IS_1020(qc) ? 352 : 360;	/* Visible sensor size */
	unsigned int originy   = 8;
	unsigned int maxheight = IS_1020(qc) ? 292 : 296;

	unsigned char control = GET_CONTROL;
	struct qc_sensor_data *sd = &qc->sensor_data;
	int r;
	unsigned int x, y;

#if HDCS_COMPRESS
	return 0;
#endif
	if (sd->subsample) {
		width *= 2;
		height *= 2;
		width  = (width + 3)/4*4;		/* Width must be multiple of 4 */
		height = (height + 3)/4*4;		/* Height must be multiple of 4 */
		sd->width = width / 2;
		sd->height = height / 2;		/* The image sent will be subsampled by 2 */
	} else {
		sd->width  = width  = (width + 3)/4*4;	/* Width must be multiple of 4 */
		sd->height = height = (height + 3)/4*4;	/* Height must be multiple of 4 */
	}
	x = (maxwidth - width)/2;			/* Center image by computing upper-left corner */
	y = (maxheight - height)/2;
	width /= 4;
	height /= 4;
	x = (x + originx)/4;				/* Must be multiple of 4 (low bits wired to 0) */
	y = (y + originy)/4;

	if ((r = qc_i2c_break(qc))<0) goto fail;
	I2C_SET_CHECK(control, 0);			/* Stop grabbing */
	I2C_SET_CHECK(HDCS_FWROW, y);
	I2C_SET_CHECK(HDCS_FWCOL, x);
	I2C_SET_CHECK(HDCS_LWROW, y+height-1);
	I2C_SET_CHECK(HDCS_LWCOL, x+width-1);
	I2C_SET_CHECK(control, BIT(2));			/* Restart grabbing */
	
	/* The exposure timings need to be recomputed when size is changed */
	x = sd->exposure;
	sd->exposure = -1;
	if ((r = hdcs_set_exposure(qc, x))<0) goto fail;
fail:	return r;
}
/* }}} */

/* {{{ [fold] struct qc_sensor qc_sensor_hdcs1000 */
const struct qc_sensor qc_sensor_hdcs1000 = {
	name:		"HDCS-1000/1100",
	manufacturer:	"Hewlett Packard",
	init:		hdcs_init,
	start:		hdcs_start,
	stop:		hdcs_stop,
	set_size:	hdcs_set_size,
	set_levels:	hdcs_set_levels,
	/* Exposure and gain control information */
	autoexposure:	FALSE,
	adapt_gainlow:	20,
	adapt_gainhigh:	20000,
	/* Information needed to access the sensor via I2C */
	reg23: 		0,
	i2c_addr: 	HDCS_ADDR,
	/* Identification information used for auto-detection */
	id_reg:		HDCS_IDENT | 1,
	id:		0x08,
	length_id:	1,
	flag:		0,
};
/* }}} */
/* {{{ [fold] struct qc_sensor qc_sensor_hdcs1020 */
const struct qc_sensor qc_sensor_hdcs1020 = {
	name:		"HDCS-1020",
	manufacturer:	"Agilent Technologies",
	init:		hdcs_init,
	start:		hdcs_start,
	stop:		hdcs_stop,
	set_size:	hdcs_set_size,
	set_levels:	hdcs_set_levels,
	/* Exposure and gain control information */
	autoexposure:	FALSE,
	adapt_gainlow:	20,
	adapt_gainhigh:	20000,
	/* Information needed to access the sensor via I2C */
	reg23: 		0,
	i2c_addr: 	HDCS_ADDR,
	/* Identification information used for auto-detection */
	id_reg:		HDCS_IDENT | 1,
	id:		0x10,
	length_id:	1,
	flag:		1,
};
/* }}} */

/* End of file */