From 04874827dbbfe036d172dd2256a7ec88ddf9d1a7 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 5 Aug 2008 10:01:44 +0200 Subject: gspca: Simplify the scan of URB packets in pac7311. From: Jean-Francois Moine Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 206 ++++++++++++++++-------------- 1 file changed, 110 insertions(+), 96 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 1b3ea1e93..0fecf4ea7 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -40,7 +40,8 @@ struct sd { unsigned char colors; unsigned char autogain; - char ffseq; + char ffnb; /* number of 'ff' in the previous frame */ + char tosof; /* number of bytes before next start of frame */ signed char ag_cnt; #define AG_CNT_START 13 }; @@ -335,6 +336,10 @@ static int sd_open(struct gspca_dev *gspca_dev) static void sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + sd->ffnb = 0; + sd->tosof = 0; reg_w(gspca_dev, 0xff, 0x01); reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); @@ -511,114 +516,123 @@ static void do_autogain(struct gspca_dev *gspca_dev) } } +/* output the jpeg header */ +static void put_jpeg_head(struct gspca_dev *gspca_dev, + struct gspca_frame *frame) +{ + unsigned char tmpbuf[4]; + + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + (__u8 *) pac7311_jpeg_header, + 12); + tmpbuf[0] = gspca_dev->height >> 8; + tmpbuf[1] = gspca_dev->height & 0xff; + tmpbuf[2] = gspca_dev->width >> 8; + tmpbuf[3] = gspca_dev->width & 0xff; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + tmpbuf, 4); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + (__u8 *) &pac7311_jpeg_header[16], + PAC7311_JPEG_HEADER_SIZE - 16); +} + +/* this function is run at interrupt level */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - unsigned char tmpbuf[4]; - int i, p, ffseq; - -/* if (len < 5) { */ - if (len < 6) { -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - - ffseq = sd->ffseq; - - for (p = 0; p < len - 6; p++) { - if ((data[0 + p] == 0xff) - && (data[1 + p] == 0xff) - && (data[2 + p] == 0x00) - && (data[3 + p] == 0xff) - && (data[4 + p] == 0x96)) { - - /* start of frame */ - if (sd->ag_cnt >= 0 && p > 28) { - sd->lum_sum += data[p - 23]; - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - atomic_set(&sd->avg_lum, - sd->lum_sum / AG_CNT_START); - sd->lum_sum = 0; - atomic_set(&sd->do_gain, 1); + int i; + +#define INTER_FRAME 0x53 +#define LUM_OFFSET 0x1e /* reverse offset / start of frame */ + + /* + * inside a frame, there may be: + * escaped ff ('ff 00') + * sequences'ff ff ff xx' to remove + * end of frame ('ff d9') + * at the end of frame, there are: + * ff d9 end of frame + * 0x33 bytes + * one byte luminosity + * 0x16 bytes + * ff ff 00 ff 96 62 44 start of frame header + */ + + if (sd->tosof == 0) { /* if inside a frame */ + + /* check for 'ff ff ff xx' at start and at end of packet */ + /* (len is always >= 3) */ + switch (sd->ffnb) { + case 1: + if (data[0] != 0xff) + break; /* keep 'ff 00' */ + /* fall thru */ + case 2: + case 3: + data += 4 - sd->ffnb; + len -= 4 - sd->ffnb; + sd->ffnb = 0; + break; + } + if (data[len - 1] == 0xff) { + if (data[len - 2] == 0xff) { + if (data[len - 3] == 0xff) { + sd->ffnb = 3; + len -= 3; + } else { + sd->ffnb = 2; + len -= 2; } + } else { + sd->ffnb = 1; + len--; } - - /* copy the end of data to the current frame */ - frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, - data, p); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - (unsigned char *) pac7311_jpeg_header, - 12); - tmpbuf[0] = gspca_dev->height >> 8; - tmpbuf[1] = gspca_dev->height & 0xff; - tmpbuf[2] = gspca_dev->width >> 8; - tmpbuf[3] = gspca_dev->width & 0xff; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - tmpbuf, 4); - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - (unsigned char *) &pac7311_jpeg_header[16], - PAC7311_JPEG_HEADER_SIZE - 16); - - data += p + 7; - len -= p + 7; - ffseq = 0; - break; } + } else { /* outside a frame */ + + /* + * get the luminosity + * and go to the start of frame + */ + data += sd->tosof; + len -= sd->tosof; + if (sd->tosof > LUM_OFFSET) + sd->lum_sum += data[-LUM_OFFSET]; + put_jpeg_head(gspca_dev, frame); + sd->tosof = 0; } - /* remove the 'ff ff ff xx' sequences */ - switch (ffseq) { - case 3: - data += 1; - len -= 1; - break; - case 2: - if (data[0] == 0xff) { - data += 2; - len -= 2; - frame->data_end -= 2; - } - break; - case 1: - if (data[0] == 0xff - && data[1] == 0xff) { - data += 3; - len -= 3; - frame->data_end -= 1; - } - break; - } - for (i = 0; i < len - 4; i++) { - if (data[i] == 0xff - && data[i + 1] == 0xff - && data[i + 2] == 0xff) { - memmove(&data[i], &data[i + 4], len - i - 4); - len -= 4; + for (i = 0; i < len; i++) { + if (data[i] != 0xff) + continue; + switch (data[i + 1]) { + case 0xd9: /* end of frame */ + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, data, i + 1); + data += INTER_FRAME; + len -= INTER_FRAME; + i = 0; + if (len > LUM_OFFSET) + sd->lum_sum += data[-LUM_OFFSET]; + if (len < 0) { + sd->tosof = -len; + break; + } + put_jpeg_head(gspca_dev, frame); + break; + case 0xff: /* 'ff ff ff xx' */ + gspca_frame_add(gspca_dev, INTER_PACKET, + frame, data, i); + data += i + 4; + len -= i + 4; + i = 0; + break; } } - ffseq = 0; - if (data[len - 4] == 0xff) { - if (data[len - 3] == 0xff - && data[len - 2] == 0xff) { - len -= 4; - } - } else if (data[len - 3] == 0xff) { - if (data[len - 2] == 0xff - && data[len - 1] == 0xff) - ffseq = 3; - } else if (data[len - 2] == 0xff) { - if (data[len - 1] == 0xff) - ffseq = 2; - } else if (data[len - 1] == 0xff) - ffseq = 1; - sd->ffseq = ffseq; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } static void getbrightness(struct gspca_dev *gspca_dev) -- cgit v1.2.3 From 2ff4bb725cf7b17813461842cd8b4d20e3fff28a Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 5 Aug 2008 11:16:19 +0200 Subject: gspca: Bug in the previous changeset about pac7311. From: Jean-Francois Moine Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 0fecf4ea7..1648c948e 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -610,13 +610,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, continue; switch (data[i + 1]) { case 0xd9: /* end of frame */ + i += 2; frame = gspca_frame_add(gspca_dev, LAST_PACKET, - frame, data, i + 1); - data += INTER_FRAME; - len -= INTER_FRAME; + frame, data, i); + data += i + INTER_FRAME; + len -= i + INTER_FRAME; i = 0; - if (len > LUM_OFFSET) + if (len > -LUM_OFFSET) sd->lum_sum += data[-LUM_OFFSET]; if (len < 0) { sd->tosof = -len; -- cgit v1.2.3 From b09fc65be0f74fa20c47c31d00ddf7553a4749ee Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Aug 2008 10:03:17 -0300 Subject: saa7134: Add NEC prococol IR decoding capability From: Mauro Carvalho Chehab This patch adds the capability of decoding NEC protocol, received via GPIO18 line. This GPIO port can trigger saa7134 IRQ. A future improvement would be to make it a little more generic to work also with GPIO16 line. A pure IRQ code didn't work, since some delays were introduced on the tests we did. A possible approach would be to use polling at a rate of 2.5 ms or less. If a new code were taken, a code similar to nec_task() could be used. However, this would add an extra overhead to kernel, and will consume more power. Due to that, we took an hybrid approach: an IRQ upper half to trigger when a new key is received and a bottom half to convert pulse-distance into a keycode. The bottom half is polling based, to improve performance. During the bottom half proccess, GPIO18 IRQ line is disabled, preventing IRQ reentrancy and improving performance a little bit. Thanks to Sistema Fenix (http://www.sistemafenix.com.br/) for sponsoring this development. Priority: normal Signed-off-by: Gilberto Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/saa7134/saa7134-input.c | 144 +++++++++++++++++++++- 1 file changed, 138 insertions(+), 6 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index f26fd7061..a9f6df2dd 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -62,8 +62,11 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " #define i2cdprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) -/** rc5 functions */ +/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ static int saa7134_rc5_irq(struct saa7134_dev *dev); +static int saa7134_nec_irq(struct saa7134_dev *dev); +static void nec_task(unsigned long data); +static void saa7134_nec_timer(unsigned long data); /* -------------------- GPIO generic keycode builder -------------------- */ @@ -280,7 +283,9 @@ void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; - if (!ir->polling && !ir->rc5_gpio) { + if (ir->nec_gpio) { + saa7134_nec_irq(dev); + } else if (!ir->polling && !ir->rc5_gpio) { build_key(dev); } else if (ir->rc5_gpio) { saa7134_rc5_irq(dev); @@ -316,6 +321,10 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir) ir->addr = 0x17; ir->rc5_key_timeout = ir_rc5_key_timeout; ir->rc5_remote_gap = ir_rc5_remote_gap; + } else if (ir->nec_gpio) { + setup_timer(&ir->timer_keyup, saa7134_nec_timer, + (unsigned long)dev); + tasklet_init(&ir->tlet, nec_task, (unsigned long)dev); } } @@ -335,6 +344,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) u32 mask_keyup = 0; int polling = 0; int rc5_gpio = 0; + int nec_gpio = 0; int ir_type = IR_TYPE_OTHER; int err; @@ -533,6 +543,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->mask_keyup = mask_keyup; ir->polling = polling; ir->rc5_gpio = rc5_gpio; + ir->nec_gpio = nec_gpio; /* init input device */ snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", @@ -679,8 +690,129 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev) return 1; } -/* ---------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: + +/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms + The first pulse (start) has 9 + 4.5 ms */ + +static void saa7134_nec_timer(unsigned long data) +{ + struct saa7134_dev *dev = (struct saa7134_dev *) data; + struct card_ir *ir = dev->remote; + + dprintk("Cancel key repeat\n"); + + ir_input_nokey(ir->dev, &ir->ir); +} + +static void nec_task(unsigned long data) +{ + struct saa7134_dev *dev = (struct saa7134_dev *) data; + struct card_ir *ir; + struct timeval tv; + int count, pulse, oldpulse, gap; + u32 ircode = 0, not_code = 0; + int ngap = 0; + + if (!data) { + printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n"); + /* GPIO will be kept disabled */ + return; + } + + ir = dev->remote; + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; + pulse = oldpulse; + + do_gettimeofday(&tv); + ir->base_time = tv; + + /* Decode NEC pulsecode. This code can take up to 76.5 ms to run. + Unfortunately, using IRQ to decode pulse didn't work, since it uses + a pulse train of 38KHz. This means one pulse on each 52 us + */ + do { + /* Wait until the end of pulse/space or 5 ms */ + for (count = 0; count < 500; count++) { + udelay(10); + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) + & ir->mask_keydown; + if (pulse != oldpulse) + break; + } + + do_gettimeofday(&tv); + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + + if (!pulse) { +#if 0 + if (!ngap && gap < 4000) + break; +#endif + /* Bit 0 has 560 us, while bit 1 has 1120 us. + Do something only if bit == 1 + */ + if (ngap && (gap > 560 + 280)) { + unsigned int shift = ngap - 1; + + /* Address first, then command */ + if (shift < 8) { + shift += 8; + ircode |= 1 << shift; + } else if (shift < 16) { + not_code |= 1 << shift; + } else if (shift < 24) { + shift -= 16; + ircode |= 1 << shift; + } else { + shift -= 24; + not_code |= 1 << shift; + } + } + ngap++; + } + + + ir->base_time = tv; + + /* TIMEOUT - Long pulse */ + if (gap >= 5000) + break; + oldpulse = pulse; + } while (ngap < 32); + + if (ngap == 32) { + /* FIXME: should check if not_code == ~ircode */ + ir->code = ir_extract_bits(ircode, ir->mask_keycode); + + dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n", + ir->code, ircode, not_code); + + ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code); + } else + dprintk("Repeat last key\n"); + + /* Keep repeating the last key */ + mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150)); + + saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); +} + +static int saa7134_nec_irq(struct saa7134_dev *dev) +{ + struct card_ir *ir = dev->remote; + + saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); + tasklet_schedule(&ir->tlet); + + return 1; +} -- cgit v1.2.3 From c6779d4098c7b706d36cb85aa23dce766af181d1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Aug 2008 10:11:25 -0300 Subject: Add support for TCL tuner MF02GIP-5N-E From: Mauro Carvalho Chehab Thanks to Sistema Fenix (http://www.sistemafenix.com.br/) and CDI Brasil (www.cdibrasil.com.br/) for sponsoring this development. Signed-off-by: Gilberto Signed-off-by: Mauro Carvalho Chehab Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/common/tuners/tuner-simple.c | 2 ++ linux/drivers/media/common/tuners/tuner-types.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c index f352af87b..a709d6bee 100644 --- a/linux/drivers/media/common/tuners/tuner-simple.c +++ b/linux/drivers/media/common/tuners/tuner-simple.c @@ -143,6 +143,7 @@ static inline int tuner_stereo(const int type, const int status) case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: case TUNER_LG_NTSC_TAPE: + case TUNER_TCL_MF02GIP_5N: return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); default: return status & TUNER_STEREO; @@ -514,6 +515,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: case TUNER_PHILIPS_FM1256_IH3: + case TUNER_TCL_MF02GIP_5N: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c index b3f0f62e0..861d23872 100644 --- a/linux/drivers/media/common/tuners/tuner-types.c +++ b/linux/drivers/media/common/tuners/tuner-types.c @@ -1217,6 +1217,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { }, }; +/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ + +static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1642,6 +1659,11 @@ struct tunertype tuners[] = { .name = "Xceive 5000 tuner", /* see xc5000.c for details */ }, + [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ + .name = "TCL tuner MF02GIP-5N-E", + .params = tuner_tcl_mf02gip_5n_params, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), + }, }; EXPORT_SYMBOL(tuners); -- cgit v1.2.3 From 4fb662a69b9c53bd1f2f01bd045a6d944fd88209 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Aug 2008 10:12:35 -0300 Subject: Fix mute on bttv driver From: Mauro Carvalho Chehab Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/bt8xx/bttv-driver.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index d5cb13e40..012eeba5e 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -3296,6 +3296,7 @@ static int bttv_open(struct inode *inode, struct file *file) sizeof(struct bttv_buffer), fh); set_tvnorm(btv,btv->tvnorm); + set_input(btv, btv->input, btv->tvnorm); btv->users++; @@ -3357,6 +3358,10 @@ static int bttv_release(struct inode *inode, struct file *file) btv->users--; bttv_field_count(btv); + + if (!btv->users) + audio_mute(btv, 1); + return 0; } -- cgit v1.2.3 From d2dbf570f863476560875eda98a939a77984aa40 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Aug 2008 10:14:13 -0300 Subject: bttv: Add support for Encore ENLTV2-FM From: Mauro Carvalho Chehab Thanks to Sistema Fenix (http://www.sistemafenix.com.br/) and CDI Brasil (www.cdibrasil.com.br/) for sponsoring this development. Priority: normal Signed-off-by: Gilberto Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/common/ir-keymaps.c | 55 ++++++++++++++++++++++-- linux/drivers/media/video/bt8xx/bttv-cards.c | 27 +++++++++++- linux/drivers/media/video/bt8xx/bttv-input.c | 62 ++++++++++++++++++++++++++-- linux/drivers/media/video/bt8xx/bttv.h | 2 +- 4 files changed, 138 insertions(+), 8 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c index a464ad34e..f1d172a3f 100644 --- a/linux/drivers/media/common/ir-keymaps.c +++ b/linux/drivers/media/common/ir-keymaps.c @@ -1842,12 +1842,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = { [ 0x41 ] = KEY_GREEN, /* AP2 */ [ 0x47 ] = KEY_YELLOW, /* AP3 */ [ 0x57 ] = KEY_BLUE, /* AP4 */ - - }; - EXPORT_SYMBOL_GPL(ir_codes_encore_enltv); +/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton + Mauro Carvalho Chehab */ +IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = { + [0x4c] = KEY_POWER2, + [0x4a] = KEY_TUNER, + [0x40] = KEY_1, + [0x60] = KEY_2, + [0x50] = KEY_3, + [0x70] = KEY_4, + [0x48] = KEY_5, + [0x68] = KEY_6, + [0x58] = KEY_7, + [0x78] = KEY_8, + [0x44] = KEY_9, + [0x54] = KEY_0, + + [0x64] = KEY_LAST, /* +100 */ + [0x4e] = KEY_AGAIN, /* Recall */ + + [0x6c] = KEY_SWITCHVIDEOMODE, /* Video Source */ + [0x5e] = KEY_MENU, + [0x56] = KEY_SCREEN, + [0x7a] = KEY_SETUP, + + [0x46] = KEY_MUTE, + [0x5c] = KEY_MODE, /* Stereo */ + [0x74] = KEY_INFO, + [0x7c] = KEY_CLEAR, + + [0x55] = KEY_UP, + [0x49] = KEY_DOWN, + [0x7e] = KEY_LEFT, + [0x59] = KEY_RIGHT, + [0x6a] = KEY_ENTER, + + [0x42] = KEY_VOLUMEUP, + [0x62] = KEY_VOLUMEDOWN, + [0x52] = KEY_CHANNELUP, + [0x72] = KEY_CHANNELDOWN, + + [0x41] = KEY_RECORD, + [0x51] = KEY_SHUFFLE, /* Snapshot */ + [0x75] = KEY_TIME, /* Timeshift */ + [0x71] = KEY_TV2, /* PIP */ + + [0x45] = KEY_REWIND, + [0x6f] = KEY_PAUSE, + [0x7d] = KEY_FORWARD, + [0x79] = KEY_STOP, +}; +EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2); + /* for the Technotrend 1500 bundled remotes (grey and black): */ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { [ 0x01 ] = KEY_POWER, diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index ff9d09f09..bf3339436 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -309,7 +309,7 @@ static struct CARD { { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, - + { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, { 0, -1, NULL } }; @@ -3069,6 +3069,31 @@ struct tvcard bttv_tvcards[] = { .has_radio = 1, .has_remote = 1, }, + [BTTV_BOARD_ENLTV_FM_2] = { + /* Encore TV Tuner Pro ENL TV-FM-2 + Mauro Carvalho Chehab IR disabled + bit 18/17 = 00 -> mute + 01 -> enable external audio input + 10 -> internal audio input (mono?) + 11 -> internal audio input + */ + .gpiomask = 0x060040, + .muxsel = { 2, 3, 3 }, + .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, + .gpiomute = 0, + .tuner_type = TUNER_TCL_MF02GIP_5N, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + } }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/linux/drivers/media/video/bt8xx/bttv-input.c b/linux/drivers/media/video/bt8xx/bttv-input.c index 09dc5ac77..a6b403a01 100644 --- a/linux/drivers/media/video/bt8xx/bttv-input.c +++ b/linux/drivers/media/video/bt8xx/bttv-input.c @@ -28,8 +28,8 @@ #include "bttvp.h" -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ +static int ir_debug; +module_param(ir_debug, int, 0644); static int repeat_delay = 500; module_param(repeat_delay, int, 0644); static int repeat_period = 33; @@ -40,6 +40,12 @@ module_param(ir_rc5_remote_gap, int, 0644); static int ir_rc5_key_timeout = 200; module_param(ir_rc5_key_timeout, int, 0644); +#undef dprintk +#define dprintk(arg...) do { \ + if (ir_debug >= 1) \ + printk(arg); \ +} while (0) + #define DEVNAME "bttv-input" /* ---------------------------------------------------------------------- */ @@ -79,6 +85,45 @@ static void ir_handle_key(struct bttv *btv) } +static void ir_enltv_handle_key(struct bttv *btv) +{ + struct card_ir *ir = btv->remote; + u32 gpio, data, keyup; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + + /* Check if it is keyup */ + keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + + if ((ir->last_gpio & 0x7f) != data) { + dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "up/down"); + + ir_input_keydown(ir->dev, &ir->ir, data, data); + if (keyup) + ir_input_nokey(ir->dev, &ir->ir); + } else { + if ((ir->last_gpio & 1 << 31) == keyup) + return; + + dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "down"); + + if (keyup) + ir_input_nokey(ir->dev, &ir->ir); + else + ir_input_keydown(ir->dev, &ir->ir, data, data); + } + + ir->last_gpio = data | keyup; +} + void bttv_input_irq(struct bttv *btv) { struct card_ir *ir = btv->remote; @@ -92,7 +137,10 @@ static void bttv_input_timer(unsigned long data) struct bttv *btv = (struct bttv*)data; struct card_ir *ir = btv->remote; - ir_handle_key(btv); + if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) + ir_enltv_handle_key(btv); + else + ir_handle_key(btv); mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } @@ -284,6 +332,14 @@ int bttv_input_init(struct bttv *btv) ir->mask_keyup = 0x006000; ir->polling = 50; /* ms */ break; + case BTTV_BOARD_ENLTV_FM_2: + ir_codes = ir_codes_encore_enltv2; + ir->mask_keycode = 0x00fd00; + ir->mask_keyup = 0x000080; + ir->polling = 1; /* ms */ + ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), + ir->mask_keycode); + break; } if (NULL == ir_codes) { dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h index 3441c0226..0f2a33eb3 100644 --- a/linux/drivers/media/video/bt8xx/bttv.h +++ b/linux/drivers/media/video/bt8xx/bttv.h @@ -177,7 +177,7 @@ #define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 #define BTTV_BOARD_GEOVISION_GV600 0x96 #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 - +#define BTTV_BOARD_ENLTV_FM_2 0x98 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 -- cgit v1.2.3 From 6bfb80222fdb109200e71e0e0a50d88a8e3c9e90 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 6 Aug 2008 08:18:38 +0200 Subject: gspca: Webcam 0c45:6128 added in sonixj. From: Jean-Francois Moine Patch adapted from a patch to gspcav1 made by the google microdia group. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/sonixj.c | 138 ++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 22 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index b30f7eeda..953f17809 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -54,8 +54,9 @@ struct sd { #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 #define SENSOR_MO4000 2 -#define SENSOR_OV7648 3 -#define SENSOR_OV7660 4 +#define SENSOR_OM6802 3 +#define SENSOR_OV7648 4 +#define SENSOR_OV7660 5 unsigned char i2c_base; }; @@ -180,6 +181,20 @@ static const __u8 sn_mo4000[] = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const __u8 sn_om6802[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf, + 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef, + 0xf7 +}; + static const __u8 sn_ov7648[] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, @@ -219,6 +234,7 @@ static const __u8 *sn_tb[] = { sn_hv7131, sn_mi0360, sn_mo4000, + sn_om6802, sn_ov7648, sn_ov7660 }; @@ -352,6 +368,40 @@ static const __u8 mo4000_sensor_init[][8] = { {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, {} }; +static __u8 om6802_sensor_init[][8] = { + {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10}, +/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */ + {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10}, + /* white balance & auto-exposure */ +/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10}, + * set color mode */ +/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10}, + * max AGC value in AE */ +/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset AGC */ +/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset brightness */ +/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset contrast */ +/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10}, + * preset gamma */ + {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10}, + /* luminance mode (0x4f = AE) */ + {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10}, + /* preset shutter */ +/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10}, + * auto frame rate */ +/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */ + +/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */ + {} +}; static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ @@ -697,29 +747,35 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - switch (sd->bridge) { + switch (sd->sensor) { + case SENSOR_OM6802: + reg_w1(gspca_dev, 0x02, 0x71); + reg_w1(gspca_dev, 0x01, 0x42); + reg_w1(gspca_dev, 0x17, 0x64); + reg_w1(gspca_dev, 0x01, 0x42); + break; + case SENSOR_OV7648: + reg_w1(gspca_dev, 0x01, 0x43); + reg_w1(gspca_dev, 0x17, 0xae); + reg_w1(gspca_dev, 0x01, 0x42); + break; #if 0 /*jfm: from win trace */ - case BRIDGE_SN9C120: + case SENSOR_OV7660: reg_w1(gspca_dev, 0x01, 0x61); reg_w1(gspca_dev, 0x17, 0x20); reg_w1(gspca_dev, 0x01, 0x60); break; #endif - case BRIDGE_SN9C325: - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0xae); - reg_w1(gspca_dev, 0x01, 0x42); - break; default: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0x61); reg_w1(gspca_dev, 0x01, 0x42); - } - - if (sd->sensor == SENSOR_HV7131R) { - if (probesensor(gspca_dev) < 0) - return -ENODEV; + if (sd->sensor == SENSOR_HV7131R) { + if (probesensor(gspca_dev) < 0) + return -ENODEV; + } + break; } return 0; } @@ -757,6 +813,16 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev) } } +static void om6802_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (om6802_sensor_init[i][0]) { + i2c_w8(gspca_dev, om6802_sensor_init[i]); + i++; + } +} + static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; @@ -916,6 +982,20 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev, | ((expoMo10[3] & 0x30) >> 4)); break; } + case SENSOR_OM6802: { + __u8 gainOm[] = + { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + if (expo > 0x03ff) + expo = 0x03ff; + if (expo < 0x0001) + expo = 0x0001; + gainOm[3] = expo >> 2; + i2c_w8(gspca_dev, gainOm); + reg_w1(gspca_dev, 0x96, expo >> 5); + PDEBUG(D_CONF, "set exposure %d", gainOm[3]); + break; + } } return expo; } @@ -926,6 +1006,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) unsigned int expo; __u8 k2; + k2 = sd->brightness >> 10; switch (sd->sensor) { case SENSOR_HV7131R: expo = sd->brightness << 4; @@ -940,9 +1021,13 @@ static void setbrightness(struct gspca_dev *gspca_dev) expo = sd->brightness >> 4; sd->exposure = setexposure(gspca_dev, expo); break; + case SENSOR_OM6802: + expo = sd->brightness >> 6; + sd->exposure = setexposure(gspca_dev, expo); + k2 = sd->brightness >> 11; + break; } - k2 = sd->brightness >> 10; reg_w1(gspca_dev, 0x96, k2); } @@ -1080,6 +1165,11 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg1 = 0x06; * 640 clk 24Mz (done) */ } break; + case SENSOR_OM6802: + om6802_InitSensor(gspca_dev); + reg1 = 0x46; /* 640 clk 24Mz */ + reg17 = 0x64; /* 640 MCKSIZE */ + break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); reg17 = 0xa2; @@ -1211,6 +1301,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) default: /* case SENSOR_MO4000: */ /* case SENSOR_MI0360: */ +/* case SENSOR_OM6802: */ expotimes = sd->exposure; expotimes += (luma_mean - delta) >> 6; if (expotimes < 0) @@ -1283,7 +1374,8 @@ static unsigned int getexposure(struct gspca_dev *gspca_dev) i2c_r5(gspca_dev, 0x09); return (gspca_dev->usb_buf[0] << 8) | gspca_dev->usb_buf[1]; - case SENSOR_MO4000: + default: +/* case SENSOR_MO4000: */ i2c_r5(gspca_dev, 0x0e); hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */ mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */ @@ -1291,7 +1383,8 @@ static unsigned int getexposure(struct gspca_dev *gspca_dev) PDEBUG(D_CONF, "exposure %d", (hexpo << 10) | (mexpo << 2) | lexpo); return (hexpo << 10) | (mexpo << 2) | lexpo; - default: +#if 0 /* keep */ +/*jfm: not called*/ /* case SENSOR_OV7648: * jfm: is it ok for 7648? */ /* case SENSOR_OV7660: */ /* read sensor exposure */ @@ -1301,7 +1394,9 @@ static unsigned int getexposure(struct gspca_dev *gspca_dev) i2c_r5(gspca_dev, 0x08); mexpo = gspca_dev->usb_buf[2]; return (hexpo << 10) | (mexpo << 2) | lexpo; +#endif } + /* not reached */ } static void getbrightness(struct gspca_dev *gspca_dev) @@ -1314,9 +1409,8 @@ static void getbrightness(struct gspca_dev *gspca_dev) sd->brightness = getexposure(gspca_dev) >> 4; break; case SENSOR_MI0360: - sd->brightness = getexposure(gspca_dev) << 4; - break; case SENSOR_MO4000: + case SENSOR_OM6802: sd->brightness = getexposure(gspca_dev) << 4; break; } @@ -1443,9 +1537,9 @@ static const __devinitdata struct usb_device_id device_table[] = { /* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C325, OV7648, 0x21)}, -/* bw600.inf: - {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, */ + {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ +/*bw600.inf:*/ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, /* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */ /* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ -- cgit v1.2.3 From 68ba76cddf919051dfaf92ad1b0d130a6dfe0b32 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 6 Aug 2008 09:11:18 +0200 Subject: gspca: The bridge/sensor of the webcam 093a:2621 is a PAC 7302. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 431 ++++++++++++++++++++---------- 1 file changed, 294 insertions(+), 137 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 1648c948e..034c00d6c 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -44,6 +44,10 @@ struct sd { char tosof; /* number of bytes before next start of frame */ signed char ag_cnt; #define AG_CNT_START 13 + + __u8 sensor; +#define SENSOR_PAC7302 0 +#define SENSOR_PAC7311 1 }; /* V4L2 controls supported by the driver */ @@ -206,9 +210,158 @@ static const __u8 pac7311_jpeg_header[] = { 0x11, 0x00, 0x3f, 0x00 }; +/* pac 7302 */ +static const __u8 probe_7302[] = { +/* index,value */ + 0xff, 0x01, /* page 1 */ + 0x78, 0x00, /* deactivate */ + 0xff, 0x01, + 0x78, 0x40, /* led off */ +}; +static const __u8 start_7302[] = { +/* index, len, [value]* */ + 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, + 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7, + 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11, + 0x26, 2, 0xaa, 0xaa, + 0x2e, 1, 0x31, + 0x38, 1, 0x01, + 0x3a, 3, 0x14, 0xff, 0x5a, + 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, + 0x00, 0x54, 0x11, + 0x55, 1, 0x00, + 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, + 0x6b, 1, 0x00, + 0x6e, 3, 0x08, 0x06, 0x00, + 0x72, 3, 0x00, 0xff, 0x00, + 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c, + 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50, + 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00, + 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9, + 0xd2, 0xeb, + 0xaf, 1, 0x02, + 0xb5, 2, 0x08, 0x08, + 0xb8, 2, 0x08, 0x88, + 0xc4, 4, 0xae, 0x01, 0x04, 0x01, + 0xcc, 1, 0x00, + 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, + 0xc1, 0xd7, 0xec, + 0xdc, 1, 0x01, + 0xff, 1, 0x01, + 0x12, 3, 0x02, 0x00, 0x01, + 0x3e, 2, 0x00, 0x00, + 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, + 0x7c, 1, 0x00, + 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, + 0x02, 0x00, + 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, + 0xc8, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, + 0x01, + 0xdb, 2, 0x00, 0x01, + 0xde, 8, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, + 0xe6, 4, 0x00, 0x00, 0x00, 0x01, + 0xeb, 1, 0x00, + 0xff, 1, 0x02, + 0x22, 1, 0x00, + 0xff, 1, 0x03, + 0x00, 255, /* load the page 3 */ + 0x11, 1, 0x01, + 0xff, 1, 0x02, + 0x13, 1, 0x00, + 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, + 0x27, 2, 0x14, 0x0c, + 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, + 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, + 0x6e, 1, 0x08, + 0xff, 1, 0x03, + 0x78, 1, 0x00, + 0, 0 /* end of sequence */ +}; + +/* page 3 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page3_7302[] = { + 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54, + 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00, + 0x00 +}; + +/* pac 7311 */ +static const __u8 probe_7311[] = { + 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ + 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ + 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */ + 0xff, 0x04, + 0x27, 0x80, + 0x28, 0xca, + 0x29, 0x53, + 0x2a, 0x0e, + 0xff, 0x01, + 0x3e, 0x20, +}; + +static const __u8 start_7311[] = { +/* index, len, [value]* */ + 0xff, 1, 0x01, + 0x02, 53, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, + 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3e, 52, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, + 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, + 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, + 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, + 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b, + 0xd0, 0xff, + 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80, + 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84, + 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14, + 0x18, 0x20, + 0x96, 3, 0x01, 0x08, 0x04, + 0xa0, 4, 0x44, 0x44, 0x44, 0x04, + 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, + 0x3f, 0x00, 0x0a, 0x01, 0x00, + 0xff, 1, 0x04, + 0x00, 254, /* load the page 4 */ + 0x11, 1, 0x01, + 0, 0 /* end of sequence */ +}; + +/* page 4 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page4_7311[] = { + 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f, + 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, + 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, + 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01, + 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 +}; + static void reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, - const char *buffer, __u16 len) + __u8 index, + const char *buffer, int len) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, @@ -221,7 +374,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, } static __u8 reg_r(struct gspca_dev *gspca_dev, - __u16 index) + __u8 index) { usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), @@ -234,7 +387,7 @@ static __u8 reg_r(struct gspca_dev *gspca_dev, } static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, + __u8 index, __u8 value) { gspca_dev->usb_buf[0] = value; @@ -246,6 +399,74 @@ static void reg_w(struct gspca_dev *gspca_dev, 500); } +static void reg_w_seq(struct gspca_dev *gspca_dev, + const __u8 *seq, int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); + seq += 2; + } +} + +/* load the beginning of a page */ +static void reg_w_page(struct gspca_dev *gspca_dev, + const __u8 *page, int len) +{ + int index; + + for (index = 0; index < len; index++) { + if (page[index] == 0xaa) /* skip this index */ + continue; + gspca_dev->usb_buf[0] = page[index]; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + } +} + +/* output a variable sequence */ +static void reg_w_var(struct gspca_dev *gspca_dev, + const __u8 *seq) +{ + int index, len; + + for (;;) { + index = *seq++; + len = *seq++; + switch (len) { + case 0: + return; + case 254: + reg_w_page(gspca_dev, page4_7311, sizeof page4_7311); + break; + case 255: + reg_w_page(gspca_dev, page3_7302, sizeof page3_7302); + break; + default: + if (len > 32) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, index, seq, len); + seq += len; + break; + } + reg_w_buf(gspca_dev, index, seq, 8); + seq += 8; + index += 8; + len -= 8; + } + } + } + /* not reached */ +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -253,22 +474,23 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - PDEBUG(D_CONF, "Find Sensor PAC7311"); - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - cam = &gspca_dev->cam; cam->epaddr = 0x05; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->sensor = id->driver_info; + if (sd->sensor == SENSOR_PAC7302) { + PDEBUG(D_CONF, "Find Sensor PAC7302"); + reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302); + + cam->cam_mode = &vga_mode[2]; /* only 640x480 */ + cam->nmodes = 1; + } else { + PDEBUG(D_CONF, "Find Sensor PAC7311"); + reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302); + + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; @@ -283,10 +505,11 @@ static void setbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int brightness; + if (sd->sensor == SENSOR_PAC7302) + return; /*jfm: inverted?*/ brightness = BRIGHTNESS_MAX - sd->brightness; reg_w(gspca_dev, 0xff, 0x04); -/* reg_w(gspca_dev, 0x0e, 0x00); */ reg_w(gspca_dev, 0x0f, brightness); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); @@ -297,6 +520,8 @@ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PAC7302) + return; reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x80, sd->contrast); /* load registers to sensor (Bit 0, auto clear) */ @@ -308,6 +533,8 @@ static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PAC7302) + return; reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x10, sd->colors); /* load registers to sensor (Bit 0, auto clear) */ @@ -340,75 +567,12 @@ static void sd_start(struct gspca_dev *gspca_dev) sd->ffnb = 0; sd->tosof = 0; - reg_w(gspca_dev, 0xff, 0x01); - reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); - reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); - reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8); - reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8); - reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); - reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3); - reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8); - reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8); - reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8); - reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8); - reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8); - reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2); - reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6); - reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8); - reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8); - reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2); - reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3); - reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4); - reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8); - reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5); - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x04); - reg_w(gspca_dev, 0x03, 0x54); - reg_w(gspca_dev, 0x04, 0x07); - reg_w(gspca_dev, 0x05, 0x2b); - reg_w(gspca_dev, 0x06, 0x09); - reg_w(gspca_dev, 0x07, 0x0f); - reg_w(gspca_dev, 0x08, 0x09); - reg_w(gspca_dev, 0x09, 0x00); - reg_w(gspca_dev, 0x0c, 0x07); - reg_w(gspca_dev, 0x0d, 0x00); - reg_w(gspca_dev, 0x0e, 0x00); - reg_w(gspca_dev, 0x0f, 0x62); - reg_w(gspca_dev, 0x10, 0x08); - reg_w(gspca_dev, 0x12, 0x07); - reg_w(gspca_dev, 0x13, 0x00); - reg_w(gspca_dev, 0x14, 0x00); - reg_w(gspca_dev, 0x15, 0x00); - reg_w(gspca_dev, 0x16, 0x00); - reg_w(gspca_dev, 0x17, 0x00); - reg_w(gspca_dev, 0x18, 0x00); - reg_w(gspca_dev, 0x19, 0x00); - reg_w(gspca_dev, 0x1a, 0x00); - reg_w(gspca_dev, 0x1b, 0x03); - reg_w(gspca_dev, 0x1c, 0xa0); - reg_w(gspca_dev, 0x1d, 0x01); - reg_w(gspca_dev, 0x1e, 0xf4); - reg_w(gspca_dev, 0x21, 0x00); - reg_w(gspca_dev, 0x22, 0x08); - reg_w(gspca_dev, 0x24, 0x03); - reg_w(gspca_dev, 0x26, 0x00); - reg_w(gspca_dev, 0x27, 0x01); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x10); - reg_w(gspca_dev, 0x2a, 0x06); - reg_w(gspca_dev, 0x2b, 0x78); - reg_w(gspca_dev, 0x2c, 0x00); - reg_w(gspca_dev, 0x2d, 0x00); - reg_w(gspca_dev, 0x2e, 0x00); - reg_w(gspca_dev, 0x2f, 0x00); - reg_w(gspca_dev, 0x30, 0x23); - reg_w(gspca_dev, 0x31, 0x28); - reg_w(gspca_dev, 0x32, 0x04); - reg_w(gspca_dev, 0x33, 0x11); - reg_w(gspca_dev, 0x34, 0x00); - reg_w(gspca_dev, 0x35, 0x00); - reg_w(gspca_dev, 0x11, 0x01); + if (sd->sensor == SENSOR_PAC7302) + reg_w_var(gspca_dev, start_7302); + else + reg_w_var(gspca_dev, start_7311); + setcontrast(gspca_dev); setbrightness(gspca_dev); setcolors(gspca_dev); @@ -416,7 +580,7 @@ static void sd_start(struct gspca_dev *gspca_dev) /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 2: /* 160x120 */ + case 2: /* 160x120 pac7311 */ reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x02, 0x03); reg_w(gspca_dev, 0xff, 0x01); @@ -426,7 +590,7 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg_w(gspca_dev, 0x80, 0x69); */ reg_w(gspca_dev, 0x87, 0x10); break; - case 1: /* 320x240 */ + case 1: /* 320x240 pac7311 */ reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x02, 0x03); reg_w(gspca_dev, 0xff, 0x01); @@ -436,6 +600,8 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x87, 0x11); break; case 0: /* 640x480 */ + if (sd->sensor == SENSOR_PAC7302) + break; reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x02, 0x03); reg_w(gspca_dev, 0xff, 0x01); @@ -448,12 +614,25 @@ static void sd_start(struct gspca_dev *gspca_dev) /* start stream */ reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x04); - reg_w(gspca_dev, 0x78, 0x05); + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0x78, 0x01); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x01); + } else { + reg_w(gspca_dev, 0x78, 0x04); + reg_w(gspca_dev, 0x78, 0x05); + } } static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0x78, 0x00); + reg_w(gspca_dev, 0x78, 0x00); + return; + } reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x27, 0x80); reg_w(gspca_dev, 0x28, 0xca); @@ -468,21 +647,17 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x40); + } } /* this function is called at close time */ static void sd_close(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ } static void do_autogain(struct gspca_dev *gspca_dev) @@ -509,10 +684,17 @@ static void do_autogain(struct gspca_dev *gspca_dev) else if (Gbright < 4) Gbright = 4; PDEBUG(D_FRAM, "gbright %d", Gbright); - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x0f, Gbright); - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x03); + reg_w(gspca_dev, 0x10, Gbright); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + } else { + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x0f, Gbright); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + } } } @@ -636,28 +818,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static void getbrightness(struct gspca_dev *gspca_dev) -{ -/* sd->brightness = reg_r(gspca_dev, 0x08); - return sd->brightness; */ -/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */ -} - -#if 0 -static void getcontrast(struct gspca_dev *gspca_dev) -{ -/* sd->contrast = reg_r(gspca_dev, 0x0e); - return sd->contrast; */ - PDEBUG(D_CONF, "getcontrast: Not implemented yet"); -} -#endif - -#if 0 -static void getcolors(struct gspca_dev *gspca_dev) -{ -} -#endif - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -672,7 +832,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -691,7 +850,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcontrast(gspca_dev); */ *val = sd->contrast; return 0; } @@ -710,7 +868,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcolors(gspca_dev); */ *val = sd->colors; return 0; } @@ -750,13 +907,13 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x2600)}, - {USB_DEVICE(0x093a, 0x2601)}, - {USB_DEVICE(0x093a, 0x2603)}, - {USB_DEVICE(0x093a, 0x2608)}, - {USB_DEVICE(0x093a, 0x260e)}, - {USB_DEVICE(0x093a, 0x260f)}, - {USB_DEVICE(0x093a, 0x2621)}, + {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From ff61b2c483facc6fd274ef18e96f60de9b2af4e4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Wed, 6 Aug 2008 15:45:38 +0200 Subject: gspca: Fix the 640x480 resolution of the webcam 093a:2621. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/sonixj.c | 1 - 1 file changed, 1 deletion(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 953f17809..7b5b92094 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -1167,7 +1167,6 @@ static void sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_OM6802: om6802_InitSensor(gspca_dev); - reg1 = 0x46; /* 640 clk 24Mz */ reg17 = 0x64; /* 640 MCKSIZE */ break; case SENSOR_OV7648: -- cgit v1.2.3 From 3152cfe67c96844ba8c651a064533925c09107b8 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 8 Aug 2008 07:59:04 +0200 Subject: gspca: Bad scanning of frames in pac7311. From: Jean-Francois Moine The previous change in packet scanning did not work, Also, autogain was no more treated at interrupt level. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 33 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 034c00d6c..730b4a1ae 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -702,8 +702,16 @@ static void do_autogain(struct gspca_dev *gspca_dev) static void put_jpeg_head(struct gspca_dev *gspca_dev, struct gspca_frame *frame) { + struct sd *sd = (struct sd *) gspca_dev; unsigned char tmpbuf[4]; + if (sd->ag_cnt >= 0) { + if (--sd->ag_cnt < 0) { + sd->ag_cnt = AG_CNT_START; + atomic_set(&sd->avg_lum, sd->lum_sum / AG_CNT_START); + atomic_set(&sd->do_gain, 1); + } + } gspca_frame_add(gspca_dev, FIRST_PACKET, frame, (__u8 *) pac7311_jpeg_header, 12); @@ -727,7 +735,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; int i; -#define INTER_FRAME 0x53 +#define INTER_FRAME 0x53 /* eof + inter frame + sof */ #define LUM_OFFSET 0x1e /* reverse offset / start of frame */ /* @@ -746,11 +754,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (sd->tosof == 0) { /* if inside a frame */ /* check for 'ff ff ff xx' at start and at end of packet */ - /* (len is always >= 3) */ + /* (len is always >= 3 and xx never ff) */ switch (sd->ffnb) { case 1: - if (data[0] != 0xff) + if (data[0] != 0xff) { /* can be '00' only */ + __u8 ff; + + sd->ffnb = 0; + ff = 0xff; + gspca_frame_add(gspca_dev, INTER_PACKET, + frame, &ff, 1); break; /* keep 'ff 00' */ + } /* fall thru */ case 2: case 3: @@ -775,16 +790,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } else { /* outside a frame */ - /* - * get the luminosity - * and go to the start of frame - */ + /* get the luminosity and go to the start of frame */ data += sd->tosof; len -= sd->tosof; if (sd->tosof > LUM_OFFSET) sd->lum_sum += data[-LUM_OFFSET]; - put_jpeg_head(gspca_dev, frame); sd->tosof = 0; + put_jpeg_head(gspca_dev, frame); } for (i = 0; i < len; i++) { @@ -792,10 +804,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, continue; switch (data[i + 1]) { case 0xd9: /* end of frame */ - i += 2; frame = gspca_frame_add(gspca_dev, LAST_PACKET, - frame, data, i); + frame, data, i + 2); data += i + INTER_FRAME; len -= i + INTER_FRAME; i = 0; @@ -816,6 +827,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, break; } } + gspca_frame_add(gspca_dev, INTER_PACKET, + frame, data, i); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -- cgit v1.2.3 From 84139cb9cd6b39f5bad49011990738d7a985e249 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 8 Aug 2008 09:31:36 +0200 Subject: gspca: Bad probe of Z-Star/Vimicro webcams with pas106 sensor. From: Hans de Goede This patch moves the detection of the 2wr SIF pas106b sensor to before detecting other sensors. Patch change by jfm: Check SIF for identified webcams only. Priority: normal Signed-off-by: Hans de Goede Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/zc3xx.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index ff0c30e4a..468b01b8f 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -6969,8 +6969,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) case SENSOR_MC501CB: return -1; /* don't probe */ case SENSOR_TAS5130C_VF0250: - /* may probe but with write in reg 0x0010 */ + /* may probe but with no write in reg 0x0010 */ return -1; /* don't probe */ + case SENSOR_PAS106: + sensor = sif_probe(gspca_dev); + if (sensor >= 0) + return sensor; + break; } sensor = vga_2wr_probe(gspca_dev); if (sensor >= 0) { @@ -6979,12 +6984,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) /* next probe is needed for OmniVision ? */ } sensor2 = vga_3wr_probe(gspca_dev); - if (sensor2 >= 0) { - if (sensor >= 0) - return sensor; - return sensor2; - } - return sif_probe(gspca_dev); + if (sensor2 >= 0 + && sensor >= 0) + return sensor; + return sensor2; } /* this function is called at probe time */ @@ -7514,14 +7517,14 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x041e)}, #ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x041e, 0x4017)}, - {USB_DEVICE(0x041e, 0x401c)}, + {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x401e)}, {USB_DEVICE(0x041e, 0x401f)}, #endif {USB_DEVICE(0x041e, 0x4029)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4034)}, - {USB_DEVICE(0x041e, 0x4035)}, + {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x4036)}, {USB_DEVICE(0x041e, 0x403a)}, #endif @@ -7553,10 +7556,10 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08d8)}, {USB_DEVICE(0x046d, 0x08da)}, {USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, - {USB_DEVICE(0x0471, 0x0325)}, - {USB_DEVICE(0x0471, 0x0326)}, - {USB_DEVICE(0x0471, 0x032d)}, - {USB_DEVICE(0x0471, 0x032e)}, + {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x055f, 0xc005)}, #ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x055f, 0xd003)}, -- cgit v1.2.3 From edde91472f7b6a4ef4f8ea24f52a451b0650ccc4 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 8 Aug 2008 09:35:25 +0200 Subject: gspca: Conflict GSPCA / ET61X251 for the webcam 102c:6251. From: Jean-Francois Moine Fix a double handling of 102c:6251 and no handling of 102c:6151 when both drivers GSPCA and ET61X251. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/etoms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c index 60b316a37..a9d043606 100644 --- a/linux/drivers/media/video/gspca/etoms.c +++ b/linux/drivers/media/video/gspca/etoms.c @@ -910,10 +910,10 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_ET61X251 {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, -#endif +#ifndef CONFIG_USB_ET61X251 {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, +#endif {} }; -- cgit v1.2.3 From ffc47339c2962593817aaa4015789dd7e6374981 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Fri, 8 Aug 2008 12:08:29 +0200 Subject: gspca: Add white balance control for spca561 rev 012A. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/spca561.c | 110 +++++++++++++++++++++++++----- 1 file changed, 92 insertions(+), 18 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 1073ac3d2..02e274452 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -34,6 +34,7 @@ struct sd { unsigned short contrast; __u8 brightness; + __u8 white; __u8 autogain; __u8 chip_revision; @@ -46,11 +47,12 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -59,12 +61,12 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 63, .step = 1, - .default_value = 32, +#define BRIGHTNESS_DEF 32 + .default_value = BRIGHTNESS_DEF, }, .set = sd_setbrightness, .get = sd_getbrightness, }, -#define SD_CONTRAST 1 { { .id = V4L2_CID_CONTRAST, @@ -73,12 +75,26 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 0x3fff, .step = 1, - .default_value = 0x2000, +#define CONTRAST_DEF 0x2000 + .default_value = CONTRAST_DEF, }, .set = sd_setcontrast, .get = sd_getcontrast, }, -#define SD_AUTOGAIN 2 + { + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "While Balance", + .minimum = 0, + .maximum = 0x7f, + .step = 1, +#define WHITE_DEF 40 + .default_value = WHITE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, { { .id = V4L2_CID_AUTOGAIN, @@ -87,7 +103,8 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, }, .set = sd_setautogain, .get = sd_getautogain, @@ -438,7 +455,7 @@ static const __u16 spca561_init_data[][2] = { {0x0035, 0x8801}, /* 0x14 - set gain general */ {0x001f, 0x8805}, /* 0x14 */ {0x0000, 0x8800}, - {0x0030, 0x8112}, + {0x000e, 0x8112}, /* white balance - was 30 */ {} }; @@ -478,9 +495,10 @@ static const __u16 Pb100_2map8300[][2] = { }; static const __u16 spca561_161rev12A_data1[][2] = { - {0x21, 0x8118}, - {0x01, 0x8114}, - {0x00, 0x8112}, + {0x29, 0x8118}, /* white balance - was 21 */ + {0x08, 0x8114}, /* white balance - was 01 */ + {0x0e, 0x8112}, /* white balance - was 00 */ + {0x00, 0x8102}, /* white balance - new */ {0x92, 0x8804}, {0x04, 0x8802}, /* windows uses 08 */ {} @@ -505,14 +523,16 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xb0, 0x8603}, /* sensor gains */ + {0x07, 0x8601}, /* white balance - new */ + {0x07, 0x8602}, /* white balance - new */ {0x00, 0x8610}, /* *red */ {0x00, 0x8611}, /* 3f *green */ {0x00, 0x8612}, /* green *blue */ {0x00, 0x8613}, /* blue *green */ - {0x35, 0x8614}, /* green *red */ - {0x35, 0x8615}, /* 40 *green */ - {0x35, 0x8616}, /* 7a *blue */ - {0x35, 0x8617}, /* 40 *green */ + {0x43, 0x8614}, /* green *red - white balance - was 0x35 */ + {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */ + {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */ + {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */ {0x0c, 0x8620}, /* 0c */ {0xc8, 0x8631}, /* c8 */ @@ -527,6 +547,7 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xdf, 0x863c}, /* df */ {0xf0, 0x8505}, {0x32, 0x850a}, + {0x99, 0x8700}, /* - white balance - new */ {} }; @@ -588,9 +609,10 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; sd->chip_revision = id->driver_info; - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->white = WHITE_DEF; return 0; } @@ -628,15 +650,18 @@ static void setcontrast(struct gspca_dev *gspca_dev) reg_w_val(dev, lowb, 0x8653); reg_w_val(dev, lowb, 0x8654); break; - case Rev012A: { + default: { +/* case Rev012A: { */ __u8 Reg8391[] = { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; /* Write camera sensor settings */ expotimes = (sd->contrast >> 5) & 0x07ff; + /* exposure is in 8309 2b, range 0120 - 5720 */ Reg8391[0] = expotimes & 0xff; /* exposure */ Reg8391[1] = 0x18 | (expotimes >> 8); Reg8391[2] = sd->brightness; /* gain */ + /* gain in 8335, 2b range 0000 - 2400 */ reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); break; @@ -644,6 +669,34 @@ static void setcontrast(struct gspca_dev *gspca_dev) } } +static void setwhite(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 white; + __u8 reg8614, reg8616; + + switch (sd->chip_revision) { + case Rev072A: + /* no such hardware */ + break; + default: +/* case Rev012A: */ + white = sd->white; + if (sd->white == 0) { + PDEBUG(D_CONF, "Discarding null whiteness"); + break; + } + /* try to emulate MS-win as possible */ + if (white < 0x45) + reg8616 = white; + else + reg8616 = 0x93 + (white >> 2); + reg8614 = 0x28 + (white >> 4); + reg_w_val(gspca_dev->dev, reg8616, 0x8616); + reg_w_val(gspca_dev->dev, reg8614, 0x8614); + } +} + static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -714,6 +767,7 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); reg_w_val(gspca_dev->dev, 0x850b, 0x03); setcontrast(gspca_dev); + setwhite(gspca_dev); break; } } @@ -721,6 +775,7 @@ static void sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { reg_w_val(gspca_dev->dev, 0x8112, 0x20); + reg_w_val(gspca_dev->dev, 0x8102, 0x00); /* white balance - new */ } static void sd_stop0(struct gspca_dev *gspca_dev) @@ -968,6 +1023,25 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* white balance - new */ +static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->white = val; + if (gspca_dev->streaming) + setwhite(gspca_dev); + return 0; +} + +static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->white; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, -- cgit v1.2.3 From 2a8a9d09b348354fafcf42ad58d376429861fcab Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2008 14:46:55 +0200 Subject: ivtv: improve CC support From: Hans Verkuil - change the work-queue to a single threaded high prio workqueue - use DMA instead of PIO for the sliced VBI data. - remove some incorrect tests - increase the internal VBI capture queue size for sliced VBI packets - ignore duplicate VBI lines With these changes it should finally be possible to get reliable closed captions. Priority: high Signed-off-by: Hans Verkuil --- linux/drivers/media/video/ivtv/ivtv-driver.c | 2 +- linux/drivers/media/video/ivtv/ivtv-driver.h | 1 + linux/drivers/media/video/ivtv/ivtv-irq.c | 29 ++++++++------------------- linux/drivers/media/video/ivtv/ivtv-queue.h | 2 +- linux/drivers/media/video/ivtv/ivtv-streams.c | 2 +- linux/drivers/media/video/ivtv/ivtv-vbi.c | 4 +++- 6 files changed, 15 insertions(+), 25 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index efdb59193..89a16bfeb 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -688,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) spin_lock_init(&itv->lock); spin_lock_init(&itv->dma_reg_lock); - itv->irq_work_queues = create_workqueue(itv->name); + itv->irq_work_queues = create_singlethread_workqueue(itv->name); if (itv->irq_work_queues == NULL) { IVTV_ERR("Could not create ivtv workqueue\n"); return -1; diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index d66ee14b6..6e0ca223a 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -252,6 +252,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ #define IVTV_F_I_INITED 21 /* set after first open */ #define IVTV_F_I_FAILED 22 /* set if first open failed */ +#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index d5ac766c1..59fe56171 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -82,6 +82,13 @@ void ivtv_irq_work_handler(void *arg) DEFINE_WAIT(wait); + if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { + struct sched_param param = { .sched_priority = 99 }; + + /* This thread must use the FIFO scheduler as it + is realtime sensitive. */ + sched_setscheduler(current, SCHED_FIFO, ¶m); + } if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) ivtv_pio_work_handler(itv); @@ -684,34 +691,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv) static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) { - struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - /* If more than two VBI buffers are pending, then - clear the old ones and start with this new one. - This can happen during transition stages when MPEG capturing is - started, but the first interrupts haven't arrived yet. During - that period VBI requests can accumulate without being able to - DMA the data. Since at most four VBI DMA buffers are available, - we just drop the old requests when there are already three - requests queued. */ - if (s->sg_pending_size > 2) { - struct ivtv_buffer *buf; - list_for_each_entry(buf, &s->q_predma.list, list) - ivtv_buf_sync_for_cpu(s, buf); - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->sg_pending_size = 0; - } - /* if we can append the data, and the MPEG stream isn't capturing, - then start a DMA request for just the VBI data. */ - if (!stream_enc_dma_append(s, data) && - !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { + if (!stream_enc_dma_append(s, data)) set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); - } } static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.h b/linux/drivers/media/video/ivtv/ivtv-queue.h index 7cfc0c9ab..476556afd 100644 --- a/linux/drivers/media/video/ivtv/ivtv-queue.h +++ b/linux/drivers/media/video/ivtv/ivtv-queue.h @@ -23,7 +23,7 @@ #define IVTV_QUEUE_H #define IVTV_DMA_UNMAPPED ((u32) -1) -#define SLICED_VBI_PIO 1 +#define SLICED_VBI_PIO 0 /* ivtv_buffer utility functions */ diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index 54d2023b2..730e85d86 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -363,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[1] = 1; /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ - data[2] = raw ? 4 : 8; + data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* The start/stop codes determine which VBI lines end up in the raw VBI data area. The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c index 71798f0da..1ce9deb11 100644 --- a/linux/drivers/media/video/ivtv/ivtv-vbi.c +++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c @@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 u32 line_size = itv->vbi.sliced_decoder_line_size; struct v4l2_decode_vbi_line vbi; int i; + unsigned lines = 0; /* find the first valid line */ for (i = 0; i < size; i++, buf++) { @@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 } vbi.p = p + 4; itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); - if (vbi.type) { + if (vbi.type && !(lines & (1 << vbi.line))) { + lines |= 1 << vbi.line; itv->vbi.sliced_data[line].id = vbi.type; itv->vbi.sliced_data[line].field = vbi.is_second_field; itv->vbi.sliced_data[line].line = vbi.line; -- cgit v1.2.3 From 3526cfc71d1a4d69c4811d3bde136d4a70e2d929 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Aug 2008 15:35:29 +0200 Subject: v4l2: add AAC bitrate control From: Hans Verkuil If you can select AAC as audio encoder, then you should also be able to set the bitrate. Add this missing control. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-common.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 0eb498a08..b5baf8f7e 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -387,6 +387,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate"; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate"; case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate"; + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode"; case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension"; @@ -549,6 +550,8 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) V4L2_MPEG_AUDIO_L3_BITRATE_32K, V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1, V4L2_MPEG_AUDIO_L3_BITRATE_192K); + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000); case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_AC3_BITRATE_32K, -- cgit v1.2.3 From f35a6467b74ef21874ce7aee3bc2728fbb22742c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 11:23:15 -0400 Subject: cxusb: add support for DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2) From: Anton Blanchard Add support for revision 2 of the DViCO FusionHDTV DVB-T Dual Digital 4 which has new tuners and demodulators (2 x DIB7070p). With this patch both DVB reception and IR works. The dib7000p driver currently hardwires the output mode to OUTMODE_MPEG2_SERIAL regardless of what we ask for. Modify it to allow OUTMODE_MPEG2_PAR_GATED_CLK to be set. Longer term we should remove the check completely and set the output mode correctly in all the callers. Add Kconfig bits to ensure the dib7000p and dib0070 modules are enabled. It would be nice to only do this for the !DVB_FE_CUSTOMISE case, but this is what the other DIB7070 module does (there are a number of module dependencies in the attach code). Priority: normal Signed-off-by: Anton Blanchard Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/dvb-usb/Kconfig | 2 + linux/drivers/media/dvb/dvb-usb/cxusb.c | 206 ++++++++++++++++++++++++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + linux/drivers/media/dvb/frontends/dib7000p.c | 3 +- 4 files changed, 211 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index e84152b75..df9932368 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -108,6 +108,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select DVB_DIB7000P + select DVB_TUNER_DIB0070 help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index aaa0b6f0b..67a3bd350 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -36,6 +36,8 @@ #include "tuner-xc2028.h" #include "tuner-simple.h" #include "mxl5005s.h" +#include "dib7000p.h" +#include "dib0070.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -726,6 +728,157 @@ no_IR: return 0; } +static struct dibx000_agc_config dib7070_agc_config = { + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + + /* + * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 + */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, +}; + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + /* refsel, sel, freq_15k */ + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, +}; + +static struct dib7000p_config cxusb_dualdig4_rev2_config = { + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = 0xfcef, + .gpio_val = 0x0110, + + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config); + + if ((adap->fe = dvb_attach(dib7000p_attach, + &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config)) == NULL) + return -EIO; + + return 0; +} + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return 0; +} + +static struct dib0070_config dib7070p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, +}; + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, + struct dvb_frontend_parameters *); +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; + } + + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + + return state->set_param_save(fe, fep); +} + +static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib7070p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 1) < 0) @@ -826,6 +979,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static struct dvb_usb_device_properties cxusb_aver_a868r_properties; @@ -852,6 +1006,9 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -876,6 +1033,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1321,6 +1479,54 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", + { NULL }, + { &cxusb_table[17], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 029b437ca..9b12261e0 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -170,6 +170,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 diff --git a/linux/drivers/media/dvb/frontends/dib7000p.c b/linux/drivers/media/dvb/frontends/dib7000p.c index c74d373b6..ebb7594e3 100644 --- a/linux/drivers/media/dvb/frontends/dib7000p.c +++ b/linux/drivers/media/dvb/frontends/dib7000p.c @@ -1359,7 +1359,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, /* Ensure the output mode remains at the previous default if it's * not specifically set by the caller. */ - if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) + if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && + (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) st->cfg.output_mode = OUTMODE_MPEG2_FIFO; demod = &st->demod; -- cgit v1.2.3 From 13b2927b565ccf92dbe49b663b758d2bfc866536 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 12:06:26 -0400 Subject: cxusb: fix checkpatch warnings & errors From: Michael Krufky Fix the following checkpatch.pl errors and warnings: ERROR: do not use assignment in if condition 117: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:819: + if ((adap->fe = dvb_attach(dib7000p_attach, ERROR: switch and case should be at the same indent 155: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:857: + switch (band) { + case BAND_VHF: offset = 950; break; + case BAND_UHF: + default: offset = 550; break; WARNING: line over 80 characters 169: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:871: + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); WARNING: line over 80 characters 213: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:1342: +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { WARNING: line over 80 characters 226: FILE: linux/drivers/media/dvb/dvb-usb/cxusb.c:1355: + .size_of_priv = sizeof(struct dib0700_adapter_state), total: 2 errors, 3 warnings, 266 lines checked Priority: normal Signed-off-by: Michael Krufky Cc: Anton Blanchard --- linux/drivers/media/dvb/dvb-usb/cxusb.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index 67a3bd350..ae560b8c7 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -816,9 +816,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &cxusb_dualdig4_rev2_config); - if ((adap->fe = dvb_attach(dib7000p_attach, - &adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config)) == NULL) + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); + if (adap->fe == NULL) return -EIO; return 0; @@ -855,9 +855,9 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, u16 offset; u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); switch (band) { - case BAND_VHF: offset = 950; break; - case BAND_UHF: - default: offset = 550; break; + case BAND_VHF: offset = 950; break; + default: + case BAND_UHF: offset = 550; break; } dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); @@ -868,7 +868,9 @@ static int dib7070_set_param_override(struct dvb_frontend *fe, static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = + dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config) == NULL) @@ -1479,7 +1481,8 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } }; -static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { +static +struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = CYPRESS_FX2, @@ -1489,10 +1492,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties .num_adapters = 1, .adapter = { { - .streaming_ctrl = cxusb_streaming_ctrl, - .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, - .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, - .size_of_priv = sizeof(struct dib0700_adapter_state), + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), /* parameter for the MPEG2-data transfer */ .stream = { .type = USB_BULK, -- cgit v1.2.3 From aa2741ad0e0d705cb706d4476091e047818f7020 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 13:21:58 -0400 Subject: fix DVB_FE_CUSTOMISE for DVB_DIB7000P and DVB_TUNER_DIB0070 with dvb-usb-cxusb From: Michael Krufky Allow dvb-usb-cxusb to be built without dib7000p or dib0070 selected Priority: normal Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/dvb-usb/Kconfig | 4 +-- linux/drivers/media/dvb/frontends/dib0070.h | 8 +++++- linux/drivers/media/dvb/frontends/dib7000p.h | 41 ++++++++++++++++++++++++---- 3 files changed, 45 insertions(+), 8 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index df9932368..8a54cb483 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -108,8 +108,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE - select DVB_DIB7000P - select DVB_TUNER_DIB0070 + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode diff --git a/linux/drivers/media/dvb/frontends/dib0070.h b/linux/drivers/media/dvb/frontends/dib0070.h index 3eedfdf50..21f2c5161 100644 --- a/linux/drivers/media/dvb/frontends/dib0070.h +++ b/linux/drivers/media/dvb/frontends/dib0070.h @@ -41,6 +41,7 @@ struct dib0070_config { extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); #else static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, @@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); -extern u16 dib0070_wbd_offset(struct dvb_frontend *); #endif diff --git a/linux/drivers/media/dvb/frontends/dib7000p.h b/linux/drivers/media/dvb/frontends/dib7000p.h index 07c4d12ed..3e8126857 100644 --- a/linux/drivers/media/dvb/frontends/dib7000p.h +++ b/linux/drivers/media/dvb/frontends/dib7000p.h @@ -41,6 +41,14 @@ struct dib7000p_config { extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, + enum dibx000_i2c_interface, + int); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]); +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, @@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); +static inline +struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, + enum dibx000_i2c_interface i, int x) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif -extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); -extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif -- cgit v1.2.3 From a09ed3d987422da2f6d14fc6e7efa295c1312629 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 12:36:51 -0400 Subject: cxusb: add lgs8gl5 and support for Magic-Pro DMB-TH usb stick From: Timothy Lee Add support for Magic-Pro DMB-TH usb stick. DMB-TH is the HDTV broadcast standard used in Hong Kong and China. [...] I've also attached a second patch against the dvb-apps repository which adds a DMB-TH scan file for Hong Kong. Since the ProHDTV stick contains a DMB-TH decoder (lgs8gl5) onboard, it outputs MPEG-TS to the PC. Priority: normal Signed-off-by: Timothy Lee Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/dvb-usb/cxusb.c | 286 +++++++++++++++ linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 2 + linux/drivers/media/dvb/frontends/Kconfig | 7 + linux/drivers/media/dvb/frontends/Makefile | 1 + linux/drivers/media/dvb/frontends/lgs8gl5.c | 480 ++++++++++++++++++++++++++ linux/drivers/media/dvb/frontends/lgs8gl5.h | 45 +++ 6 files changed, 821 insertions(+) create mode 100644 linux/drivers/media/dvb/frontends/lgs8gl5.c create mode 100644 linux/drivers/media/dvb/frontends/lgs8gl5.h (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index ae560b8c7..49985f992 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -38,6 +38,7 @@ #include "mxl5005s.h" #include "dib7000p.h" #include "dib0070.h" +#include "lgs8gl5.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -111,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); } +static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, + u8 addr, int onoff) +{ + u8 o[2] = {addr, onoff}; + u8 i; + int rc; + + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc < 0) + return rc; + if (i == 0x01) + return 0; + else { + deb_info("gpio_write failed.\n"); + return -EIO; + } +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -264,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) return rc; } +static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 b; + ret = cxusb_power_ctrl(d, onoff); + if (!onoff) + return ret; + + msleep(128); + cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); + msleep(100); + return ret; +} + static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -285,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } +static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) +{ + int ep = d->props.generic_bulk_ctrl_endpoint; + const int timeout = 100; + const int junk_len = 32; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) +{ + struct usb_data_stream_properties *p = &d->props.adapter[0].stream; + const int timeout = 100; + const int junk_len = p->u.bulk.buffersize; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static int cxusb_d680_dmb_streaming_ctrl( + struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) { + u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); + return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, + buf, sizeof(buf), NULL, 0); + } else { + int ret = cxusb_ctrl_msg(adap->dev, + CMD_STREAMING_OFF, NULL, 0, NULL, 0); + return ret; + } +} + static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { struct dvb_usb_rc_key *keymap = d->props.rc_key_map; @@ -337,6 +432,32 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, return 0; } +static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[2]; + int i; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) + return 0; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[0] && + keymap[i].data == ircode[1]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -424,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ }; +static struct dvb_usb_rc_key d680_dmb_rc_keys[] = { + { 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */ + { 0x08, 0x0c, KEY_ZOOM }, + { 0x08, 0x00, KEY_0 }, + { 0x00, 0x01, KEY_1 }, + { 0x08, 0x02, KEY_2 }, + { 0x00, 0x03, KEY_3 }, + { 0x08, 0x04, KEY_4 }, + { 0x00, 0x05, KEY_5 }, + { 0x08, 0x06, KEY_6 }, + { 0x00, 0x07, KEY_7 }, + { 0x08, 0x08, KEY_8 }, + { 0x00, 0x09, KEY_9 }, + { 0x00, 0x0a, KEY_MUTE }, + { 0x08, 0x29, KEY_BACK }, + { 0x00, 0x12, KEY_CHANNELUP }, + { 0x08, 0x13, KEY_CHANNELDOWN }, + { 0x00, 0x2b, KEY_VOLUMEUP }, + { 0x08, 0x2c, KEY_VOLUMEDOWN }, + { 0x00, 0x20, KEY_UP }, + { 0x08, 0x21, KEY_DOWN }, + { 0x00, 0x11, KEY_LEFT }, + { 0x08, 0x10, KEY_RIGHT }, + { 0x00, 0x0d, KEY_OK }, + { 0x08, 0x1f, KEY_RECORD }, + { 0x00, 0x17, KEY_PLAYPAUSE }, + { 0x08, 0x16, KEY_PLAYPAUSE }, + { 0x00, 0x0b, KEY_STOP }, + { 0x08, 0x27, KEY_FASTFORWARD }, + { 0x00, 0x26, KEY_REWIND }, + { 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */ + { 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */ + { 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */ + { 0x00, 0x25, KEY_POWER }, +}; + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -529,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = { .AgcMasterByte = 0x00, }; +/* FIXME: needs tweaking */ +static struct mxl5005s_config d680_dmb_tuner = { + .i2c_address = 0x63, + .if_freq = 36125000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -617,6 +794,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &d680_dmb_tuner); + return (fe == NULL) ? -EIO : 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -906,6 +1091,54 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static struct lgs8gl5_config lgs8gl5_cfg = { + .demod_address = 0x19, +}; + +static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + int n; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + + /* Drain USB pipes to avoid hang after reboot */ + for (n = 0; n < 5; n++) { + cxusb_d680_dmb_drain_message(d); + cxusb_d680_dmb_drain_video(d); + msleep(200); + } + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -985,6 +1218,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static struct dvb_usb_device_properties cxusb_aver_a868r_properties; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1011,6 +1245,8 @@ static int cxusb_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_rev2_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -1036,6 +1272,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1530,6 +1767,55 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { } }; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_d680_dmb_frontend_attach, + .tuner_attach = cxusb_d680_dmb_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = d680_dmb_rc_keys, + .rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys), + .rc_query = cxusb_d680_dmb_rc_query, + + .num_device_descs = 1, + .devices = { + { + "Conexant DMB-TH Stick", + { NULL }, + { &cxusb_table[18], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 9b12261e0..851070b86 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -22,6 +22,7 @@ #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CONEXANT 0x0572 #define USB_VID_CYPRESS 0x04b4 #define USB_VID_DIBCOM 0x10b8 #define USB_VID_DPOSH 0x1498 @@ -69,6 +70,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 +#define USB_PID_CONEXANT_D680_DMB 0x86d6 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index 7dbb4a223..774f5c2a7 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -385,4 +385,11 @@ config DVB_ISL6421 help An SEC control chip. +config DVB_LGS8GL5 + tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + endmenu diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 028da5561..262eaa429 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o +obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o diff --git a/linux/drivers/media/dvb/frontends/lgs8gl5.c b/linux/drivers/media/dvb/frontends/lgs8gl5.c new file mode 100644 index 000000000..c0a223d28 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c @@ -0,0 +1,480 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include "dvb_frontend.h" +#include "lgs8gl5.h" + + +#define REG_RESET 0x02 +#define REG_RESET_OFF 0x01 +#define REG_03 0x03 +#define REG_04 0x04 +#define REG_07 0x07 +#define REG_09 0x09 +#define REG_0A 0x0a +#define REG_0B 0x0b +#define REG_0C 0x0c +#define REG_37 0x37 +#define REG_STRENGTH 0x4b +#define REG_STRENGTH_MASK 0x7f +#define REG_STRENGTH_CARRIER 0x80 +#define REG_INVERSION 0x7c +#define REG_INVERSION_ON 0x80 +#define REG_7D 0x7d +#define REG_7E 0x7e +#define REG_A2 0xa2 +#define REG_STATUS 0xa4 +#define REG_STATUS_SYNC 0x04 +#define REG_STATUS_LOCK 0x01 + + +struct lgs8gl5_state { + struct i2c_adapter *i2c; + const struct lgs8gl5_config *config; + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "lgs8gl5: " args); \ + } while (0) + + +/* Writes into demod's register */ +static int +lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = {reg, data}; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", + __func__, reg, data, ret); + return (ret != 1) ? -1 : 0; +} + + +/* Reads from demod's register */ +static int +lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) +{ + int ret, j; + u8 b0[] = {reg}; + u8 b1[] = {0}; + struct i2c_msg msg[2] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return -EIO; + + return b1[0]; +} + + +static int +lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + lgs8gl5_read_reg(state, reg); + lgs8gl5_write_reg(state, reg, data); + return 0; +} + + +/* Writes into alternate device's register */ +/* TODO: Find out what that device is for! */ +static int +lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret, j; + u8 b0[] = {reg}; + u8 b1[] = {0}; + u8 b2[] = {reg, data}; + struct i2c_msg msg[3] = { + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b2, + .len = 2 + }, + }; + + ret = i2c_transfer(state->i2c, msg, 3); + return (ret != 3) ? -1 : 0; +} + + +static void +lgs8gl5_soft_reset(struct lgs8gl5_state *state) +{ + u8 val; + + dprintk("%s\n", __func__); + + val = lgs8gl5_read_reg(state, REG_RESET); + lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); + lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); + msleep(5); +} + + +static int +lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) +{ + u8 val; + + dprintk("%s\n", __func__); + + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val | REG_INVERSION_ON); + case INVERSION_OFF: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val & ~REG_INVERSION_ON); + default: + return -EINVAL; + } +} + + +/* Starts demodulation */ +static void +lgs8gl5_start_demod(struct lgs8gl5_state *state) +{ + u8 val; + int n; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + lgs8gl5_update_reg(state, REG_03, 0x00); + lgs8gl5_update_reg(state, REG_7E, 0x01); + lgs8gl5_update_alt_reg(state, 0xc5, 0x00); + lgs8gl5_update_reg(state, REG_04, 0x02); + lgs8gl5_update_reg(state, REG_37, 0x01); + lgs8gl5_soft_reset(state); + + /* Wait for carrier */ + for (n = 0; n < 10; n++) { + val = lgs8gl5_read_reg(state, REG_STRENGTH); + dprintk("Wait for carrier[%d] 0x%02X\n", n, val); + if (val & REG_STRENGTH_CARRIER) + break; + msleep(4); + } + if (!(val & REG_STRENGTH_CARRIER)) + return; + + /* Wait for lock */ + for (n = 0; n < 20; n++) { + val = lgs8gl5_read_reg(state, REG_STATUS); + dprintk("Wait for lock[%d] 0x%02X\n", n, val); + if (val & REG_STATUS_LOCK) + break; + msleep(12); + } + if (!(val & REG_STATUS_LOCK)) + return; + + lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); + lgs8gl5_soft_reset(state); +} + + +static int +lgs8gl5_init(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + return 0; +} + + +static int +lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + u8 flags = lgs8gl5_read_reg(state, REG_STATUS); + + *status = 0; + + if ((level & REG_STRENGTH_MASK) > 0) + *status |= FE_HAS_SIGNAL; + if (level & REG_STRENGTH_CARRIER) + *status |= FE_HAS_CARRIER; + if (flags & REG_STATUS_SYNC) + *status |= FE_HAS_SYNC; + if (flags & REG_STATUS_LOCK) + *status |= FE_HAS_LOCK; + + return 0; +} + + +static int +lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + *ber = 0; + + return 0; +} + + +static int +lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *signal_strength = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *snr = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + *ucblocks = 0; + + return 0; +} + + +static int +lgs8gl5_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* lgs8gl5_set_inversion(state, p->inversion); */ + + lgs8gl5_start_demod(state); + + return 0; +} + + +static int +lgs8gl5_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); + struct dvb_ofdm_parameters *o = &p->u.ofdm; + + p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; + + o->code_rate_HP = FEC_1_2; + o->code_rate_LP = FEC_7_8; + o->guard_interval = GUARD_INTERVAL_1_32; + o->transmission_mode = TRANSMISSION_MODE_2K; + o->constellation = QAM_64; + o->hierarchy_information = HIERARCHY_NONE; + o->bandwidth = BANDWIDTH_8_MHZ; + + return 0; +} + + +static int +lgs8gl5_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 240; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + + +static void +lgs8gl5_release(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + kfree(state); +} + + +static struct dvb_frontend_ops lgs8gl5_ops; + + +struct dvb_frontend* +lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) +{ + struct lgs8gl5_state *state = NULL; + + dprintk("%s\n", __func__); + + /* Allocate memory for the internal state */ + state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + + /* Check if the demod is there */ + if (lgs8gl5_read_reg(state, REG_RESET) < 0) + goto error; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &lgs8gl5_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgs8gl5_attach); + + +static struct dvb_frontend_ops lgs8gl5_ops = { + .info = { + .name = "Legend Silicon LGS-8GL5 DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = lgs8gl5_release, + + .init = lgs8gl5_init, + + .set_frontend = lgs8gl5_set_frontend, + .get_frontend = lgs8gl5_get_frontend, + .get_tune_settings = lgs8gl5_get_tune_settings, + + .read_status = lgs8gl5_read_status, + .read_ber = lgs8gl5_read_ber, + .read_signal_strength = lgs8gl5_read_signal_strength, + .read_snr = lgs8gl5_read_snr, + .read_ucblocks = lgs8gl5_read_ucblocks, +}; + + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); +MODULE_AUTHOR("Timothy Lee"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/lgs8gl5.h b/linux/drivers/media/dvb/frontends/lgs8gl5.h new file mode 100644 index 000000000..d14176787 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgs8gl5.h @@ -0,0 +1,45 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef LGS8GL5_H +#define LGS8GL5_H + +#include + +struct lgs8gl5_config { + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_LGS8GL5) || \ + (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) +extern struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGS8GL5 */ + +#endif /* LGS8GL5_H */ -- cgit v1.2.3 From 7fd7d21d543d90ecf1086f9c5909bd4c01cf69ae Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 9 Aug 2008 14:29:46 -0400 Subject: lgs8gl5: fix build warnings From: Michael Krufky Fix the following build warnings: lgs8gl5.c: In function 'lgs8gl5_read_reg': lgs8gl5.c:95: warning: unused variable 'j' lgs8gl5.c: In function 'lgs8gl5_update_alt_reg': lgs8gl5.c:135: warning: unused variable 'j' lgs8gl5.c: In function 'lgs8gl5_read_ber': lgs8gl5.c:300: warning: unused variable 'state' lgs8gl5.c: In function 'lgs8gl5_read_ucblocks': lgs8gl5.c:332: warning: unused variable 'state' lgs8gl5.c: At top level: lgs8gl5.c:181: warning: 'lgs8gl5_set_inversion' defined but not used Priority: normal Signed-off-by: Michael Krufky --- linux/drivers/media/dvb/frontends/lgs8gl5.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/dvb/frontends/lgs8gl5.c b/linux/drivers/media/dvb/frontends/lgs8gl5.c index c0a223d28..380ae1868 100644 --- a/linux/drivers/media/dvb/frontends/lgs8gl5.c +++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c @@ -92,7 +92,7 @@ lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) static int lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) { - int ret, j; + int ret; u8 b0[] = {reg}; u8 b1[] = {0}; struct i2c_msg msg[2] = { @@ -132,7 +132,7 @@ lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) static int lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) { - int ret, j; + int ret; u8 b0[] = {reg}; u8 b1[] = {0}; u8 b2[] = {reg, data}; @@ -175,7 +175,7 @@ lgs8gl5_soft_reset(struct lgs8gl5_state *state) msleep(5); } - +#if 0 static int lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) { @@ -198,7 +198,7 @@ lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) return -EINVAL; } } - +#endif /* Starts demodulation */ static void @@ -297,7 +297,6 @@ lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) static int lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct lgs8gl5_state *state = fe->demodulator_priv; *ber = 0; return 0; @@ -329,7 +328,6 @@ lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) static int lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct lgs8gl5_state *state = fe->demodulator_priv; *ucblocks = 0; return 0; -- cgit v1.2.3 From 820cd3d979980715c200c58479a5160fb7ca73f5 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 11 Aug 2008 10:26:51 +0200 Subject: gspca: Remove the unused field 'dev_name' of the device structure. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/gspca.h | 1 - linux/drivers/media/video/gspca/pac207.c | 1 - linux/drivers/media/video/gspca/spca561.c | 1 - 3 files changed, 3 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 67e448940..5cb584546 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -56,7 +56,6 @@ extern int gspca_debug; /* device information - set at probe time */ struct cam { - char *dev_name; struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; __u8 epaddr; diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 7ef18d578..cee45b048 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -271,7 +271,6 @@ static int sd_config(struct gspca_dev *gspca_dev, " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x05; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 02e274452..a9f7c99e6 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -602,7 +602,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ cam->cam_mode = sif_mode; -- cgit v1.2.3 From 77258a45e913a4808c3b25bd893a60d96a0e3778 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 11 Aug 2008 11:13:12 +0200 Subject: gspca: Big rewrite of spca561. From: Jean-Francois Moine Bug register/value inversions in USB exchanges. Exposure and gain controls added for rev 12a. Separate the functions and controls of the revisions 12a and 72a. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/spca561.c | 595 ++++++++++++++++++------------ 1 file changed, 351 insertions(+), 244 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index a9f7c99e6..075699433 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -32,85 +32,44 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned short contrast; - __u8 brightness; - __u8 white; + __u16 contrast; /* rev72a only */ +#define CONTRAST_MIN 0x0000 +#define CONTRAST_DEF 0x2000 +#define CONTRAST_MAX 0x3fff + + __u16 exposure; /* rev12a only */ +#define EXPOSURE_MIN 0x0120 +#define EXPOSURE_DEF 0x20ae +#define EXPOSURE_MAX 0x5720 + + __u8 brightness; /* rev72a only */ +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_DEF 32 +#define BRIGHTNESS_MAX 63 + + __u8 white; /* rev12a only */ +#define WHITE_MIN 0 +#define WHITE_DEF 0x40 +#define WHITE_MAX 0x7f + __u8 autogain; +#define AUTOGAIN_MIN 0 +#define AUTOGAIN_DEF 1 +#define AUTOGAIN_MAX 1 + + __u8 gain; /* rev12a only */ +#define GAIN_MIN 0x0 +#define GAIN_DEF 0x24 +#define GAIN_MAX 0x24 __u8 chip_revision; +#define Rev012A 0 +#define Rev072A 1 + signed char ag_cnt; #define AG_CNT_START 13 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static struct ctrl sd_ctrls[] = { - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 63, - .step = 1, -#define BRIGHTNESS_DEF 32 - .default_value = BRIGHTNESS_DEF, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0x3fff, - .step = 1, -#define CONTRAST_DEF 0x2000 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, - { - { - .id = V4L2_CID_DO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "While Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, -#define WHITE_DEF 40 - .default_value = WHITE_DEF, - }, - .set = sd_setwhite, - .get = sd_getwhite, - }, - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - static struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, @@ -160,12 +119,8 @@ static struct v4l2_pix_format sif_mode[] = { #define SPCA561_INDEX_I2C_BASE 0x8800 #define SPCA561_SNAPBIT 0x20 #define SPCA561_SNAPCTRL 0x40 -enum { - Rev072A = 0, - Rev012A, -}; -static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value) +static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) { int ret; @@ -215,12 +170,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); } -static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode) -{ - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, mode, 0x8802); -} - static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) { int retry = 60; @@ -229,9 +178,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) DataLow = valeur; DataHight = valeur >> 8; - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, DataLow, 0x8805); - reg_w_val(gspca_dev->dev, DataHight, 0x8800); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8805, DataLow); + reg_w_val(gspca_dev->dev, 0x8800, DataHight); while (retry--) { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf[0]) @@ -245,9 +194,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) __u8 value; __u8 vallsb; - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802); + reg_w_val(gspca_dev->dev, 0x8804, 0x92); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01)); while (retry--) { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf) @@ -459,6 +408,7 @@ static const __u16 spca561_init_data[][2] = { {} }; +#if 0 static void sensor_reset(struct gspca_dev *gspca_dev) { reg_w_val(gspca_dev->dev, 0x8631, 0xc8); @@ -466,10 +416,12 @@ static void sensor_reset(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8112, 0x00); reg_w_val(gspca_dev->dev, 0x8114, 0x00); reg_w_val(gspca_dev->dev, 0x8118, 0x21); - i2c_init(gspca_dev, 0x14); - i2c_write(gspca_dev, 1, 0x0d); - i2c_write(gspca_dev, 0, 0x0d); + reg_w_val(gspca_dev->dev, 0x8804, 0x92); /* i2c init */ + reg_w_val(gspca_dev->dev, 0x8802, 0x14); + i2c_write(gspca_dev, 0x0001, 0x0d); + i2c_write(gspca_dev, 0x0000, 0x0d); } +#endif /******************** QC Express etch2 stuff ********************/ static const __u16 Pb100_1map8300[][2] = { @@ -479,9 +431,9 @@ static const __u16 Pb100_1map8300[][2] = { {0x8303, 0x0125}, /* image area */ {0x8304, 0x0169}, {0x8328, 0x000b}, - {0x833c, 0x0001}, + {0x833c, 0x0001}, /*fixme: win:07*/ - {0x832f, 0x0419}, + {0x832f, 0x1904}, /*fixme: was 0419*/ {0x8307, 0x00aa}, {0x8301, 0x0003}, {0x8302, 0x000e}, @@ -547,7 +499,7 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xdf, 0x863c}, /* df */ {0xf0, 0x8505}, {0x32, 0x850a}, - {0x99, 0x8700}, /* - white balance - new */ +/* {0x99, 0x8700}, * - white balance - new (removed) */ {} }; @@ -566,9 +518,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev, } static void init_161rev12A(struct gspca_dev *gspca_dev) { - sensor_reset(gspca_dev); +/* sensor_reset(gspca_dev); (not in win) */ write_vector(gspca_dev, spca561_161rev12A_data1); sensor_mapwrite(gspca_dev, Pb100_1map8300); +/*fixme: should be in sd_start*/ write_vector(gspca_dev, spca561_161rev12A_data2); sensor_mapwrite(gspca_dev, Pb100_2map8300); } @@ -605,32 +558,29 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + cam->nmodes = ARRAY_SIZE(sif_mode); sd->chip_revision = id->driver_info; sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; - sd->autogain = AUTOGAIN_DEF; sd->white = WHITE_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->gain = GAIN_DEF; return 0; } /* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +static int sd_open_12a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->chip_revision) { - case Rev072A: - PDEBUG(D_STREAM, "Chip revision id: 072a"); - write_vector(gspca_dev, spca561_init_data); - break; - default: -/* case Rev012A: */ - PDEBUG(D_STREAM, "Chip revision id: 012a"); - init_161rev12A(gspca_dev); - break; - } + PDEBUG(D_STREAM, "Chip revision: 012a"); + init_161rev12A(gspca_dev); + return 0; +} +static int sd_open_72a(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_STREAM, "Chip revision: 072a"); + write_vector(gspca_dev, spca561_init_data); return 0; } @@ -639,61 +589,82 @@ static void setcontrast(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; __u8 lowb; - int expotimes; switch (sd->chip_revision) { case Rev072A: lowb = sd->contrast >> 8; - reg_w_val(dev, lowb, 0x8651); - reg_w_val(dev, lowb, 0x8652); - reg_w_val(dev, lowb, 0x8653); - reg_w_val(dev, lowb, 0x8654); + reg_w_val(dev, 0x8651, lowb); + reg_w_val(dev, 0x8652, lowb); + reg_w_val(dev, 0x8653, lowb); + reg_w_val(dev, 0x8654, lowb); break; default: { /* case Rev012A: { */ +#if 1 + static const __u8 Reg8391[] = + { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 }; + + reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); + reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); +#else + int expotimes; __u8 Reg8391[] = { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; +/*fixme: does not work..*/ /* Write camera sensor settings */ - expotimes = (sd->contrast >> 5) & 0x07ff; + expotimes = sd->contrast >> 5; /* exposure is in 8309 2b, range 0120 - 5720 */ - Reg8391[0] = expotimes & 0xff; /* exposure */ + Reg8391[0] = expotimes; /* exposure */ Reg8391[1] = 0x18 | (expotimes >> 8); Reg8391[2] = sd->brightness; /* gain */ /* gain in 8335, 2b range 0000 - 2400 */ reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); +#endif break; } } } +/* rev12a only */ static void setwhite(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u16 white; __u8 reg8614, reg8616; - switch (sd->chip_revision) { - case Rev072A: - /* no such hardware */ - break; - default: -/* case Rev012A: */ - white = sd->white; - if (sd->white == 0) { - PDEBUG(D_CONF, "Discarding null whiteness"); - break; - } - /* try to emulate MS-win as possible */ - if (white < 0x45) - reg8616 = white; - else - reg8616 = 0x93 + (white >> 2); - reg8614 = 0x28 + (white >> 4); - reg_w_val(gspca_dev->dev, reg8616, 0x8616); - reg_w_val(gspca_dev->dev, reg8614, 0x8614); + white = sd->white; + if (sd->white == 0) { + PDEBUG(D_CONF, "Discarding null whiteness"); + return; } + /* try to emulate MS-win as possible */ + if (white < 0x45) + reg8616 = white; + else + reg8616 = 0x93 + (white >> 2); + reg8614 = 0x28 + (white >> 4); + reg_w_val(gspca_dev->dev, 0x8616, reg8616); + reg_w_val(gspca_dev->dev, 0x8614, reg8614); +} + +/* rev 12a only */ +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + reg_w_val(dev, 0x8309, sd->gain); +} + +/* rev 12a only */ +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + + reg_w_val(dev, 0x8335, sd->gain); } static void setautogain(struct gspca_dev *gspca_dev) @@ -708,67 +679,67 @@ static void setautogain(struct gspca_dev *gspca_dev) } } -static void sd_start(struct gspca_dev *gspca_dev) +static void sd_start_12a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; int Clck; __u8 Reg8307[] = { 0xaa, 0x00 }; int mode; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - switch (sd->chip_revision) { - case Rev072A: - switch (mode) { - default: -/* case 0: - case 1: */ - Clck = 0x25; - break; - case 2: - Clck = 0x22; - break; - case 3: - Clck = 0x21; - break; - } - reg_w_val(dev, 0x8500, mode); /* mode */ - reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ - reg_w_val(dev, 0x8112, 0x10 | 0x20); - setautogain(gspca_dev); + switch (mode) { + case 0: + case 1: + Clck = 0x8a; + break; + case 2: + Clck = 0x85; break; default: -/* case Rev012A: */ - switch (mode) { - case 0: - case 1: - Clck = 0x8a; - break; - case 2: - Clck = 0x85; - break; - default: - Clck = 0x83; - break; - } - if (mode <= 1) { - /* Use compression on 320x240 and above */ - reg_w_val(dev, 0x8500, 0x10 | mode); - } else { - /* I couldn't get the compression to work below 320x240 - * Fortunately at these resolutions the bandwidth - * is sufficient to push raw frames at ~20fps */ - reg_w_val(dev, 0x8500, mode); - } /* -- qq@kuku.eu.org */ - reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); - reg_w_val(gspca_dev->dev, 0x8700, Clck); - /* 0x8f 0x85 0x27 clock */ - reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); - reg_w_val(gspca_dev->dev, 0x850b, 0x03); - setcontrast(gspca_dev); - setwhite(gspca_dev); + Clck = 0x83; + break; + } + if (mode <= 1) { + /* Use compression on 320x240 and above */ + reg_w_val(dev, 0x8500, 0x10 | mode); + } else { + /* I couldn't get the compression to work below 320x240 + * Fortunately at these resolutions the bandwidth + * is sufficient to push raw frames at ~20fps */ + reg_w_val(dev, 0x8500, mode); + } /* -- qq@kuku.eu.org */ + reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); + reg_w_val(gspca_dev->dev, 0x8700, Clck); + /* 0x8f 0x85 0x27 clock */ + reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev->dev, 0x850b, 0x03); + setcontrast(gspca_dev); + setwhite(gspca_dev); +} +static void sd_start_72a(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int Clck; + int mode; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (mode) { + default: +/* case 0: + case 1: */ + Clck = 0x25; + break; + case 2: + Clck = 0x22; + break; + case 3: + Clck = 0x21; break; } + reg_w_val(dev, 0x8500, mode); /* mode */ + reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(dev, 0x8112, 0x10 | 0x20); + setautogain(gspca_dev); } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -787,6 +758,7 @@ static void sd_close(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8114, 0); } +/* rev72a only */ static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -895,24 +867,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } +/* rev 72a only */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 value; - switch (sd->chip_revision) { - case Rev072A: - value = sd->brightness; - reg_w_val(gspca_dev->dev, value, 0x8611); - reg_w_val(gspca_dev->dev, value, 0x8612); - reg_w_val(gspca_dev->dev, value, 0x8613); - reg_w_val(gspca_dev->dev, value, 0x8614); - break; - default: -/* case Rev012A: */ - setcontrast(gspca_dev); - break; - } + value = sd->brightness; + reg_w_val(gspca_dev->dev, 0x8611, value); + reg_w_val(gspca_dev->dev, 0x8612, value); + reg_w_val(gspca_dev->dev, 0x8613, value); + reg_w_val(gspca_dev->dev, 0x8614, value); } static void getbrightness(struct gspca_dev *gspca_dev) @@ -920,52 +885,38 @@ static void getbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8611, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8612, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8613, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8614, 1); - tot += gspca_dev->usb_buf[0]; - sd->brightness = tot >> 2; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8611, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8612, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8613, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8614, 1); + tot += gspca_dev->usb_buf[0]; + sd->brightness = tot >> 2; } +/* rev72a only */ static void getcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8651, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8652, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8653, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8654, 1); - tot += gspca_dev->usb_buf[0]; - sd->contrast = tot << 6; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8651, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8652, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8653, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8654, 1); + tot += gspca_dev->usb_buf[0]; + sd->contrast = tot << 6; PDEBUG(D_CONF, "get contrast %d", sd->contrast); } +/* rev 72a only */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -985,6 +936,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev 72a only */ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1022,7 +974,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -/* white balance - new */ +/* rev12a only */ static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1041,20 +993,173 @@ static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev12a only */ +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +/* rev12a only */ +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +/* control tables */ +static struct ctrl sd_ctrls_12a[] = { + { + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "While Balance", + .minimum = WHITE_MIN, + .maximum = WHITE_MAX, + .step = 1, + .default_value = WHITE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = EXPOSURE_MIN, + .maximum = EXPOSURE_MAX, + .step = 1, + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = GAIN_MIN, + .maximum = GAIN_MAX, + .step = 1, + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct ctrl sd_ctrls_72a[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = BRIGHTNESS_MIN, + .maximum = BRIGHTNESS_MAX, + .step = 1, + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = CONTRAST_MIN, + .maximum = CONTRAST_MAX, + .step = 1, + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + /* sub-driver description */ -static const struct sd_desc sd_desc = { +static const struct sd_desc sd_desc_12a = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .ctrls = sd_ctrls_12a, + .nctrls = ARRAY_SIZE(sd_ctrls_12a), .config = sd_config, - .open = sd_open, - .start = sd_start, + .open = sd_open_12a, + .start = sd_start_12a, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, +/* .dq_callback = do_autogain, * fixme */ +}; +static const struct sd_desc sd_desc_72a = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_72a, + .nctrls = ARRAY_SIZE(sd_ctrls_72a), + .config = sd_config, + .open = sd_open_72a, + .start = sd_start_72a, .stopN = sd_stopN, .stop0 = sd_stop0, .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; +static const struct sd_desc *sd_desc[2] = { + &sd_desc_12a, + &sd_desc_72a +}; /* -- module initialisation -- */ static const __devinitdata struct usb_device_id device_table[] = { @@ -1082,7 +1187,9 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + return gspca_dev_probe(intf, id, + sd_desc[id->driver_info], + sizeof(struct sd), THIS_MODULE); } -- cgit v1.2.3 From 1ed2472d509f192f2420635f87057f0d53345ed6 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 11 Aug 2008 17:06:20 +0200 Subject: gspca: Bad frame scanning again and bad init in pac7311. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 62 +++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 730b4a1ae..85d9ddbc5 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -220,6 +220,7 @@ static const __u8 probe_7302[] = { }; static const __u8 start_7302[] = { /* index, len, [value]* */ + 0xff, 1, 0x00, /* page 0 */ 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, @@ -249,7 +250,7 @@ static const __u8 start_7302[] = { 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, 0xc1, 0xd7, 0xec, 0xdc, 1, 0x01, - 0xff, 1, 0x01, + 0xff, 1, 0x01, /* page 1 */ 0x12, 3, 0x02, 0x00, 0x01, 0x3e, 2, 0x00, 0x00, 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, @@ -257,26 +258,26 @@ static const __u8 start_7302[] = { 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, 0x02, 0x00, 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, - 0xc8, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, - 0x01, + 0xd8, 1, 0x01, 0xdb, 2, 0x00, 0x01, - 0xde, 8, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, + 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, 0xe6, 4, 0x00, 0x00, 0x00, 0x01, 0xeb, 1, 0x00, - 0xff, 1, 0x02, + 0xff, 1, 0x02, /* page 2 */ 0x22, 1, 0x00, - 0xff, 1, 0x03, + 0xff, 1, 0x03, /* page 3 */ 0x00, 255, /* load the page 3 */ 0x11, 1, 0x01, - 0xff, 1, 0x02, + 0xff, 1, 0x02, /* page 2 */ 0x13, 1, 0x00, 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, 0x27, 2, 0x14, 0x0c, 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, 0x6e, 1, 0x08, - 0xff, 1, 0x03, + 0xff, 1, 0x03, /* page 1 */ 0x78, 1, 0x00, 0, 0 /* end of sequence */ }; @@ -321,14 +322,14 @@ static const __u8 probe_7311[] = { static const __u8 start_7311[] = { /* index, len, [value]* */ - 0xff, 1, 0x01, - 0x02, 53, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, + 0xff, 1, 0x01, /* page 1 */ + 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3e, 52, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, + 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, @@ -342,7 +343,7 @@ static const __u8 start_7311[] = { 0xa0, 4, 0x44, 0x44, 0x44, 0x04, 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, 0x3f, 0x00, 0x0a, 0x01, 0x00, - 0xff, 1, 0x04, + 0xff, 1, 0x04, /* page 4 */ 0x00, 254, /* load the page 4 */ 0x11, 1, 0x01, 0, 0 /* end of sequence */ @@ -738,6 +739,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, #define INTER_FRAME 0x53 /* eof + inter frame + sof */ #define LUM_OFFSET 0x1e /* reverse offset / start of frame */ +/*fixme:test+*/ +/* dump the packet */ + if (gspca_debug & 0x200) { + static char tmp[50]; + + PDEBUG(0x200, "pkt_scan"); + tmp[0] = 0; + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i != 0) { + PDEBUG(0x200, "%s", tmp); + tmp[0] = 0; + } + sprintf(&tmp[(i % 16) * 3], "%02x ", data[i]); + } + if (tmp[0] != 0) + PDEBUG(0x200, "%s", tmp); + } +/*fixme:test-*/ /* * inside a frame, there may be: * escaped ff ('ff 00') @@ -819,6 +838,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, put_jpeg_head(gspca_dev, frame); break; case 0xff: /* 'ff ff ff xx' */ +/*fixme:test+*/ +/* is there a start of frame ? */ + if (data[i + 2] == 0x00) { + static __u8 ffd9[2] = {0xff, 0xd9}; + + gspca_frame_add(gspca_dev, + INTER_PACKET, + frame, data, + i + 7 - INTER_FRAME); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, ffd9, 2); + data += i + 7; + len -= i + 7; + i = 0; + put_jpeg_head(gspca_dev, frame); + break; + } +/*fixme:test-*/ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, i); data += i + 4; -- cgit v1.2.3 From d2e97898c7f8009430bfe79e0024051b1b6b6030 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Mon, 11 Aug 2008 20:14:52 +0200 Subject: gspca: Webcam 0c45:612e added in sonixj. From: Jean-Francois Moine Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/sonixj.c | 118 +++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 7b5b92094..2c76f02ce 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -55,8 +55,9 @@ struct sd { #define SENSOR_MI0360 1 #define SENSOR_MO4000 2 #define SENSOR_OM6802 3 -#define SENSOR_OV7648 4 -#define SENSOR_OV7660 5 +#define SENSOR_OV7630 4 +#define SENSOR_OV7648 5 +#define SENSOR_OV7660 6 unsigned char i2c_base; }; @@ -195,6 +196,17 @@ static const __u8 sn_om6802[] = { 0xf7 }; +static const __u8 sn_ov7630[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static const __u8 sn_ov7648[] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, @@ -235,6 +247,7 @@ static const __u8 *sn_tb[] = { sn_mi0360, sn_mo4000, sn_om6802, + sn_ov7630, sn_ov7648, sn_ov7660 }; @@ -402,6 +415,56 @@ static __u8 om6802_sensor_init[][8] = { /* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */ {} }; +static const __u8 ov7630_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/* win: loop on 2 wwrite, 1 read */ + {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, + {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10}, + {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10}, + {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10}, + {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10}, + {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10}, + {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10}, + {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10}, + {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10}, + {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10}, + {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10}, + {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/*fixme: + 0x12, 0x04*/ + {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, + {} +}; static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ @@ -754,6 +817,14 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x17, 0x64); reg_w1(gspca_dev, 0x01, 0x42); break; +#if 0 +/*jfm: from win trace */ + case SENSOR_OV7630: + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0xe2); + reg_w1(gspca_dev, 0x01, 0x60); + break; +#endif case SENSOR_OV7648: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0xae); @@ -823,6 +894,19 @@ static void om6802_InitSensor(struct gspca_dev *gspca_dev) } } +static void ov7630_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + i2c_w8(gspca_dev, ov7630_sensor_init[i]); + i++; + msleep(20); + while (ov7630_sensor_init[i][0]) { + i2c_w8(gspca_dev, ov7630_sensor_init[i]); + i++; + } +} + static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; @@ -1085,8 +1169,8 @@ static void sd_start(struct gspca_dev *gspca_dev) static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ - static const __u8 CE_sn9c325[] = - { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ + static const __u8 CE_ov76xx[] = + { 0x32, 0xdd, 0x32, 0xdd }; /* OV7630/48 */ sn9c1xx = sn_tb[(int) sd->sensor]; configure_gpio(gspca_dev, sn9c1xx); @@ -1104,13 +1188,16 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0xc8, 0x50); reg_w1(gspca_dev, 0xc9, 0x3c); reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); - switch (sd->bridge) { - case BRIDGE_SN9C325: + switch (sd->sensor) { + case SENSOR_OV7630: + reg17 = 0xe2; + break; + case SENSOR_OV7648: reg17 = 0xae; break; -#if 0 +#if 1 /*jfm: from win trace */ - case BRIDGE_SN9C120: + case SENSOR_OV7660: reg17 = 0xa0; break; #endif @@ -1169,6 +1256,11 @@ static void sd_start(struct gspca_dev *gspca_dev) om6802_InitSensor(gspca_dev); reg17 = 0x64; /* 640 MCKSIZE */ break; + case SENSOR_OV7630: + ov7630_InitSensor(gspca_dev); + reg17 = 0xe2; + reg1 = 0x40; + break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); reg17 = 0xa2; @@ -1199,9 +1291,10 @@ static void sd_start(struct gspca_dev *gspca_dev) } reg_w(gspca_dev, 0xc0, C0, 6); reg_w(gspca_dev, 0xca, CA, 4); - switch (sd->bridge) { - case BRIDGE_SN9C325: - reg_w(gspca_dev, 0xce, CE_sn9c325, 4); + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: + reg_w(gspca_dev, 0xce, CE_ov76xx, 4); break; default: reg_w(gspca_dev, 0xce, CE, 4); @@ -1245,6 +1338,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) i2c_w8(gspca_dev, stopmi0360); data = 0x29; break; + case SENSOR_OV7630: case SENSOR_OV7648: data = 0x29; break; @@ -1540,7 +1634,7 @@ static const __devinitdata struct usb_device_id device_table[] = { /*bw600.inf:*/ {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, -/* {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)}, /* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ #ifndef CONFIG_USB_SN9C102 {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, -- cgit v1.2.3 From acca17a2d0197a622e05ca0f16d07700d5d83b6d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Aug 2008 19:06:12 +0200 Subject: v4l2: fix for kernels <= 2.6.17 From: Hans Verkuil class and devt should also be set for kernels 2.6.16 and 2.6.17. This was the case originally, but unfortunately an earlier patch of mine inadvertently left in an incorrect #if/#endif pair. Priority: normal Signed-off-by: Hans Verkuil --- linux/drivers/media/video/v4l2-dev.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c index 398376a40..d97320091 100644 --- a/linux/drivers/media/video/v4l2-dev.c +++ b/linux/drivers/media/video/v4l2-dev.c @@ -356,10 +356,8 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, /* sysfs class */ memset(&vfd->dev, 0x00, sizeof(vfd->dev)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) vfd->dev.class = &video_class; vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) if (vfd->parent) vfd->dev.dev = vfd->parent; -- cgit v1.2.3 From bf23e05b3f443503624b55cb16f32afdcb74289c Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Thu, 14 Aug 2008 10:50:14 +0200 Subject: gspca: Pixmap PJPG (Pixart 73xx JPEG) added, generated by pac7311. From: Jean-Francois Moine The JPEG frames generated by the Pixart 73xx have: - special markers 'ff ff ff xx' every 1024/512 bytes, - unused 8 bits at end of JPEG blocks, and then ask for a new pixel format. Priority: normal Signed-off-by: Jean-Francois Moine --- linux/drivers/media/video/gspca/pac7311.c | 173 +++--------------------------- 1 file changed, 15 insertions(+), 158 deletions(-) (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 85d9ddbc5..c148d1003 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -22,6 +22,7 @@ #define MODULE_NAME "pac7311" #include "gspca.h" +#include "jpeg.h" MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7311"); @@ -40,7 +41,6 @@ struct sd { unsigned char colors; unsigned char autogain; - char ffnb; /* number of 'ff' in the previous frame */ char tosof; /* number of bytes before next start of frame */ signed char ag_cnt; #define AG_CNT_START 13 @@ -121,95 +121,23 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; -#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */ - -static const __u8 pac7311_jpeg_header[] = { - 0xff, 0xd8, - 0xff, 0xe0, 0x00, 0x03, 0x20, - 0xff, 0xc0, 0x00, 0x11, 0x08, - 0x01, 0xe0, /* 12: height */ - 0x02, 0x80, /* 14: width */ - 0x03, /* 16 */ - 0x01, 0x21, 0x00, - 0x02, 0x11, 0x01, - 0x03, 0x11, 0x01, - 0xff, 0xdb, 0x00, 0x84, - 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, - 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, - 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, - 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, - 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f, - 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64, - 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18, - 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, - 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, - 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, - 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, - 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, - 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, - 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, - 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, - 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, - 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, - 0x11, 0x00, 0x3f, 0x00 -}; - /* pac 7302 */ static const __u8 probe_7302[] = { /* index,value */ @@ -566,7 +494,6 @@ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - sd->ffnb = 0; sd->tosof = 0; if (sd->sensor == SENSOR_PAC7302) @@ -699,34 +626,6 @@ static void do_autogain(struct gspca_dev *gspca_dev) } } -/* output the jpeg header */ -static void put_jpeg_head(struct gspca_dev *gspca_dev, - struct gspca_frame *frame) -{ - struct sd *sd = (struct sd *) gspca_dev; - unsigned char tmpbuf[4]; - - if (sd->ag_cnt >= 0) { - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - atomic_set(&sd->avg_lum, sd->lum_sum / AG_CNT_START); - atomic_set(&sd->do_gain, 1); - } - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - (__u8 *) pac7311_jpeg_header, - 12); - tmpbuf[0] = gspca_dev->height >> 8; - tmpbuf[1] = gspca_dev->height & 0xff; - tmpbuf[2] = gspca_dev->width >> 8; - tmpbuf[3] = gspca_dev->width & 0xff; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - tmpbuf, 4); - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - (__u8 *) &pac7311_jpeg_header[16], - PAC7311_JPEG_HEADER_SIZE - 16); -} - /* this function is run at interrupt level */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ @@ -739,7 +638,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, #define INTER_FRAME 0x53 /* eof + inter frame + sof */ #define LUM_OFFSET 0x1e /* reverse offset / start of frame */ -/*fixme:test+*/ +#if 0 /*fixme:test+*/ /* dump the packet */ if (gspca_debug & 0x200) { static char tmp[50]; @@ -756,7 +655,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (tmp[0] != 0) PDEBUG(0x200, "%s", tmp); } -/*fixme:test-*/ +#endif /*fixme:test-*/ /* * inside a frame, there may be: * escaped ff ('ff 00') @@ -767,47 +666,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, * 0x33 bytes * one byte luminosity * 0x16 bytes - * ff ff 00 ff 96 62 44 start of frame header + * ff ff 00 ff 96 62 44 start of frame */ - if (sd->tosof == 0) { /* if inside a frame */ - - /* check for 'ff ff ff xx' at start and at end of packet */ - /* (len is always >= 3 and xx never ff) */ - switch (sd->ffnb) { - case 1: - if (data[0] != 0xff) { /* can be '00' only */ - __u8 ff; - - sd->ffnb = 0; - ff = 0xff; - gspca_frame_add(gspca_dev, INTER_PACKET, - frame, &ff, 1); - break; /* keep 'ff 00' */ - } - /* fall thru */ - case 2: - case 3: - data += 4 - sd->ffnb; - len -= 4 - sd->ffnb; - sd->ffnb = 0; - break; - } - if (data[len - 1] == 0xff) { - if (data[len - 2] == 0xff) { - if (data[len - 3] == 0xff) { - sd->ffnb = 3; - len -= 3; - } else { - sd->ffnb = 2; - len -= 2; - } - } else { - sd->ffnb = 1; - len--; - } - } - } else { /* outside a frame */ + if (sd->tosof != 0) { /* if outside a frame */ /* get the luminosity and go to the start of frame */ data += sd->tosof; @@ -815,14 +677,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (sd->tosof > LUM_OFFSET) sd->lum_sum += data[-LUM_OFFSET]; sd->tosof = 0; - put_jpeg_head(gspca_dev, frame); + jpeg_put_header(gspca_dev, frame, 1, 0x21); } for (i = 0; i < len; i++) { if (data[i] != 0xff) continue; switch (data[i + 1]) { - case 0xd9: /* end of frame */ + case 0xd9: /* 'ff d9' end of frame */ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, i + 2); @@ -835,11 +697,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, sd->tosof = -len; break; } - put_jpeg_head(gspca_dev, frame); + jpeg_put_header(gspca_dev, frame, 1, 0x21); break; - case 0xff: /* 'ff ff ff xx' */ -/*fixme:test+*/ +#if 0 /*fixme:test+*/ /* is there a start of frame ? */ + case 0xff: /* 'ff ff' */ if (data[i + 2] == 0x00) { static __u8 ffd9[2] = {0xff, 0xd9}; @@ -853,16 +715,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data += i + 7; len -= i + 7; i = 0; - put_jpeg_head(gspca_dev, frame); + jpeg_put_header(gspca_dev, frame, 1, 0x21); break; } -/*fixme:test-*/ - gspca_frame_add(gspca_dev, INTER_PACKET, - frame, data, i); - data += i + 4; - len -= i + 4; - i = 0; break; +#endif /*fixme:test-*/ } } gspca_frame_add(gspca_dev, INTER_PACKET, -- cgit v1.2.3 From a499d8eb7179d0990c06b89c3362af960c7d9eef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Aug 2008 21:00:11 +0300 Subject: Remove the dead CONFIG_RADIO_MIROPCM20{,_RDS} code From: Adrian Bunk The CONFIG_RADIO_MIROPCM20{,_RDS} code became dead code 1.5 years ago. Priority: normal Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/radio/Makefile | 4 - linux/drivers/media/radio/miropcm20-radio.c | 267 ------------------------- linux/drivers/media/radio/miropcm20-rds-core.c | 212 -------------------- linux/drivers/media/radio/miropcm20-rds-core.h | 19 -- linux/drivers/media/radio/miropcm20-rds.c | 140 ------------- 5 files changed, 642 deletions(-) delete mode 100644 linux/drivers/media/radio/miropcm20-radio.c delete mode 100644 linux/drivers/media/radio/miropcm20-rds-core.c delete mode 100644 linux/drivers/media/radio/miropcm20-rds-core.h delete mode 100644 linux/drivers/media/radio/miropcm20-rds.c (limited to 'linux/drivers/media') diff --git a/linux/drivers/media/radio/Makefile b/linux/drivers/media/radio/Makefile index a30159f6f..7ca71ab96 100644 --- a/linux/drivers/media/radio/Makefile +++ b/linux/drivers/media/radio/Makefile @@ -2,8 +2,6 @@ # Makefile for the kernel character device drivers. # -miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o - obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o @@ -14,8 +12,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o -obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o diff --git a/linux/drivers/media/radio/miropcm20-radio.c b/linux/drivers/media/radio/miropcm20-radio.c deleted file mode 100644 index efbb9cce8..000000000 --- a/linux/drivers/media/radio/miropcm20-radio.c +++ /dev/null @@ -1,267 +0,0 @@ -/* Miro PCM20 radio driver for Linux radio support - * (c) 1998 Ruurd Reitsma - * Thanks to Norberto Pellici for the ACI device interface specification - * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/aci.c) - * Look there for further info... - */ - -/* Revision history: - * - * 1998 Ruurd Reitsma - * 2000-09-05 Robert Siemer - * removed unfinished volume control (maybe adding it later again) - * use OSS-mixer; added stereo control - */ - -/* What ever you think about the ACI, version 0x07 is not very well! - * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono - * conditions... Robert - */ - -#include -#include -#include "compat.h" -#include -#include -#include -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -struct pcm20_device { - unsigned long freq; - int muted; - int stereo; -}; - - -static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) -{ - dev->muted = mute; - return aci_write_cmd(ACI_SET_TUNERMUTE, mute); -} - -static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) -{ - dev->stereo = stereo; - return aci_write_cmd(ACI_SET_TUNERMONO, !stereo); -} - -static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) -{ - unsigned char freql; - unsigned char freqh; - - dev->freq=freq; - - freq /= 160; - if (!(aci_version==0x07 || aci_version>=0xb0)) - freq /= 10; /* I don't know exactly which version - * needs this hack */ - freql = freq & 0xff; - freqh = freq >> 8; - - aci_rds_cmd(RDS_RESET, NULL, 0); - pcm20_stereo(dev, 1); - - return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh); -} - -static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) -{ - /* okay, check for signal, stereo and rds here... */ - int i; - unsigned char buf; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0) - return i; - pr_debug("check_sig: 0x%x\n", i); - if (i & 0x80) { - /* no signal from tuner */ - *flags=0; - *signal=0; - return 0; - } else - *signal=0xffff; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0) - return i; - if (i & 0x40) { - *flags=0; - } else { - /* stereo */ - *flags=VIDEO_TUNER_STEREO_ON; - /* I can't see stereo, when forced to mono */ - dev->stereo=1; - } - - if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) - return i; - if (buf & 1) - /* RDS available */ - *flags|=VIDEO_TUNER_RDS_ON; - else - return 0; - - if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) - return i; - pr_debug("rds-signal: %d\n", buf); - if (buf > 15) { - printk("miropcm20-radio: RX strengths unexpected high...\n"); - buf=15; - } - /* refine signal */ - if ((*signal=SCALE(15, 0xffff, buf))==0) - *signal = 1; - - return 0; -} - -static int pcm20_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct pcm20_device *pcm20 = dev->priv; - int i; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability *v = arg; - memset(v,0,sizeof(*v)); - v->type=VID_TYPE_TUNER; - strcpy(v->name, "Miro PCM20"); - v->channels=1; - v->audios=1; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - if(v->tuner) /* Only 1 tuner */ - return -EINVAL; - v->rangelow=87*16000; - v->rangehigh=108*16000; - pcm20_getflags(pcm20, &v->flags, &v->signal); - v->flags|=VIDEO_TUNER_LOW; - v->mode=VIDEO_MODE_AUTO; - strcpy(v->name, "FM"); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - if(v->tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = pcm20->freq; - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *freq = arg; - pcm20->freq = *freq; - i=pcm20_setfreq(pcm20, pcm20->freq); - pr_debug("First view (setfreq): 0x%x\n", i); - return i; - } - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - memset(v,0, sizeof(*v)); - v->flags=VIDEO_AUDIO_MUTABLE; - if (pcm20->muted) - v->flags|=VIDEO_AUDIO_MUTE; - v->mode=VIDEO_SOUND_STEREO; - if (pcm20->stereo) - v->mode|=VIDEO_SOUND_MONO; - /* v->step=2048; */ - strcpy(v->name, "Radio"); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - if(v->audio) - return -EINVAL; - - pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE)); - if(v->flags&VIDEO_SOUND_MONO) - pcm20_stereo(pcm20, 0); - if(v->flags&VIDEO_SOUND_STEREO) - pcm20_stereo(pcm20, 1); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int pcm20_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl); -} - -static struct pcm20_device pcm20_unit = { - .freq = 87*16000, - .muted = 1, -}; - -static const struct file_operations pcm20_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = pcm20_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = v4l_compat_ioctl32, -#endif - .llseek = no_llseek, -}; - -static struct video_device pcm20_radio = { - .name = "Miro PCM 20 radio", - .fops = &pcm20_fops, - .priv = &pcm20_unit -}; - -static int __init pcm20_init(void) -{ - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1) - goto video_register_device; - - if(attach_aci_rds()<0) - goto attach_aci_rds; - - printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - - return 0; - - attach_aci_rds: - video_unregister_device(&pcm20_radio); - video_register_device: - return -EINVAL; -} - -MODULE_AUTHOR("Ruurd Reitsma"); -MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); -MODULE_LICENSE("GPL"); - -static void __exit pcm20_cleanup(void) -{ - unload_aci_rds(); - video_unregister_device(&pcm20_radio); -} - -module_init(pcm20_init); -module_exit(pcm20_cleanup); diff --git a/linux/drivers/media/radio/miropcm20-rds-core.c b/linux/drivers/media/radio/miropcm20-rds-core.c deleted file mode 100644 index e18e2a4a8..000000000 --- a/linux/drivers/media/radio/miropcm20-rds-core.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Many thanks to Fred Seidel , the - * designer of the RDS decoder hardware. With his help - * I was able to code this driver. - * Thanks also to Norberto Pellicci, Dominic Mounteney - * and www.teleauskunft.de - * for good hints on finding Fred. It was somewhat hard - * to locate him here in Germany... [: - * - * Revision history: - * - * 2000-08-09 Robert Siemer - * RDS support for MiroSound PCM20 radio - */ - -#include -#include -#include -#include -#include -#include "compat.h" -#include - -#include -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -#define DEBUG 0 - -static struct mutex aci_rds_mutex; - -#define RDS_DATASHIFT 2 /* Bit 2 */ -#define RDS_DATAMASK (1 << RDS_DATASHIFT) -#define RDS_BUSYMASK 0x10 /* Bit 4 */ -#define RDS_CLOCKMASK 0x08 /* Bit 3 */ - -#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1) - - -#if DEBUG -static void print_matrix(char array[], unsigned int length) -{ - int i, j; - - for (i=0; i=0; j--) { - printk("%d", (array[i] >> j) & 0x1); - } - if (i%8 == 0) - printk(" byte-border\n"); - else - printk("\n"); - } -} -#endif /* DEBUG */ - -static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) -{ - int i; - - if (size != 8) - return -1; - for (i = 7; i >= 0; i--) - sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; - sendbuffer[0] |= RDS_CLOCKMASK; - - return 0; -} - -static int rds_waitread(void) -{ - unsigned char byte; - int i=2000; - - do { - byte=inb(RDS_REGISTER); - i--; - } - while ((byte & RDS_BUSYMASK) && i); - - if (i) { - #if DEBUG - printk(KERN_DEBUG "rds_waitread()"); - print_matrix(&byte, 1); - #endif - return (byte); - } else { - printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n"); - return -1; - } -} - -/* don't use any ..._nowait() function if you are not sure what you do... */ - -static inline void rds_rawwrite_nowait(unsigned char byte) -{ - #if DEBUG - printk(KERN_DEBUG "rds_rawwrite()"); - print_matrix(&byte, 1); - #endif - outb(byte, RDS_REGISTER); -} - -static int rds_rawwrite(unsigned char byte) -{ - if (rds_waitread() >= 0) { - rds_rawwrite_nowait(byte); - return 0; - } else - return -1; -} - -static int rds_write(unsigned char cmd) -{ - unsigned char sendbuffer[8]; - int i; - - if (byte2trans(cmd, sendbuffer, 8) != 0){ - return -1; - } else { - for (i=0; i<8; i++) { - rds_rawwrite(sendbuffer[i]); - } - } - return 0; -} - -static int rds_readcycle_nowait(void) -{ - rds_rawwrite_nowait(0); - return rds_waitread(); -} - -static int rds_readcycle(void) -{ - if (rds_rawwrite(0) < 0) - return -1; - return rds_waitread(); -} - -static int rds_read(unsigned char databuffer[], int datasize) -{ - #define READSIZE (8*datasize) - - int i,j; - - if (datasize < 1) /* nothing to read */ - return 0; - - /* to be able to use rds_readcycle_nowait() - I have to waitread() here */ - if (rds_waitread() < 0) - return -1; - - memset(databuffer, 0, datasize); - - for (i=0; i< READSIZE; i++) - if((j=rds_readcycle_nowait()) < 0) { - return -1; - } else { - databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8))); - } - - return 0; -} - -static int rds_ack(void) -{ - int i=rds_readcycle(); - - if (i < 0) - return -1; - if (i & RDS_DATAMASK) { - return 0; /* ACK */ - } else { - printk(KERN_DEBUG "aci-rds: NACK\n"); - return 1; /* NACK */ - } -} - -int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) -{ - int ret; - - if (mutex_lock_interruptible(&aci_rds_mutex)) - return -EINTR; - - rds_write(cmd); - - /* RDS_RESET doesn't need further processing */ - if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) - ret = -1; - else - ret = 0; - - mutex_unlock(&aci_rds_mutex); - - return ret; -} -EXPORT_SYMBOL(aci_rds_cmd); - -int __init attach_aci_rds(void) -{ - mutex_init(&aci_rds_mutex); - return 0; -} - -void __exit unload_aci_rds(void) -{ -} -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/radio/miropcm20-rds-core.h b/linux/drivers/media/radio/miropcm20-rds-core.h deleted file mode 100644 index aeb5761f0..000000000 --- a/linux/drivers/media/radio/miropcm20-rds-core.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _MIROPCM20_RDS_CORE_H_ -#define _MIROPCM20_RDS_CORE_H_ - -extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); - -#define RDS_STATUS 0x01 -#define RDS_STATIONNAME 0x02 -#define RDS_TEXT 0x03 -#define RDS_ALTFREQ 0x04 -#define RDS_TIMEDATE 0x05 -#define RDS_PI_CODE 0x06 -#define RDS_PTYTATP 0x07 -#define RDS_RESET 0x08 -#define RDS_RXVALUE 0x09 - -extern void __exit unload_aci_rds(void); -extern int __init attach_aci_rds(void); - -#endif /* _MIROPCM20_RDS_CORE_H_ */ diff --git a/linux/drivers/media/radio/miropcm20-rds.c b/linux/drivers/media/radio/miropcm20-rds.c deleted file mode 100644 index af90cdcf2..000000000 --- a/linux/drivers/media/radio/miropcm20-rds.c +++ /dev/null @@ -1,140 +0,0 @@ -/* MiroSOUND PCM20 radio rds interface driver - * (c) 2001 Robert Siemer - * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information. - */ - -/* Revision history: - * - * 2001-04-18 Robert Siemer - * separate file for user interface driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "miropcm20-rds-core.h" - -static char * text_buffer; -static int rds_users; - - -static int rds_f_open(struct inode *in, struct file *fi) -{ - if (rds_users) - return -EBUSY; - - lock_kernel(); - rds_users++; - if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) { - rds_users--; - printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n"); - unlock_kernel(); - return -ENOMEM; - } - - unlock_kernel(); - return 0; -} - -static int rds_f_release(struct inode *in, struct file *fi) -{ - kfree(text_buffer); - - rds_users--; - return 0; -} - -static void print_matrix(char *ch, char out[]) -{ - int j; - - for (j=7; j>=0; j--) { - out[7-j] = ((*ch >> j) & 0x1) + '0'; - } -} - -static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) -{ -// i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset); - - char c; - char bits[8]; - - msleep(2000); - aci_rds_cmd(RDS_STATUS, &c, 1); - print_matrix(&c, bits); - if (copy_to_user(buffer, bits, 8)) - return -EFAULT; - -/* if ((c >> 3) & 1) { - aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8); - text_buffer[0] = ' ' ; - text_buffer[9] = '\n'; - return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18; - } -*/ -/* if ((c >> 6) & 1) { - aci_rds_cmd(RDS_PTYTATP, &c, 1); - if ( c & 1) - sprintf(text_buffer, " M"); - else - sprintf(text_buffer, " S"); - if ((c >> 1) & 1) - sprintf(text_buffer+2, " TA"); - else - sprintf(text_buffer+2, " --"); - if ((c >> 7) & 1) - sprintf(text_buffer+5, " TP"); - else - sprintf(text_buffer+5, " --"); - sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f); - return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20; - } -*/ - - if ((c >> 4) & 1) { - aci_rds_cmd(RDS_TEXT, text_buffer, 65); - text_buffer[0] = ' ' ; - text_buffer[65] = '\n'; - return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8; - } else { - put_user('\n', buffer+8); - return 9; - } -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) -static const struct file_operations rds_fops = { -#else -static struct file_operations rds_fops = { -#endif - .owner = THIS_MODULE, - .read = rds_f_read, - .open = rds_f_open, - .release = rds_f_release -}; - -static struct miscdevice rds_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "radiotext", - .fops = &rds_fops, -}; - -static int __init miropcm20_rds_init(void) -{ - return misc_register(&rds_miscdev); -} - -static void __exit miropcm20_rds_cleanup(void) -{ - misc_deregister(&rds_miscdev); -} - -module_init(miropcm20_rds_init); -module_exit(miropcm20_rds_cleanup); -MODULE_LICENSE("GPL"); -- cgit v1.2.3