summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/em28xx
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-11-20 10:58:02 -0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-11-20 10:58:02 -0200
commit4bed69bfcb36161bcd89a7a61b6a912c32fea813 (patch)
treeb40092bb4cc41424343b1a4fd3d90b63f7f01fb3 /linux/drivers/media/video/em28xx
parentf7addb7035dedd9ba701c586fec16b234dde4a77 (diff)
parentc6f9ed52d0eb5d04c1c65914976d81315a872839 (diff)
downloadmediapointer-dvb-s2-4bed69bfcb36161bcd89a7a61b6a912c32fea813.tar.gz
mediapointer-dvb-s2-4bed69bfcb36161bcd89a7a61b6a912c32fea813.tar.bz2
merge: http://linuxtv.org/hg/~pinchartl/uvcvideo
From: Mauro Carvalho Chehab <mchehab@redhat.com> Priority: normal Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video/em28xx')
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c12
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c383
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c357
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c21
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c327
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h121
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c67
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h68
8 files changed, 1080 insertions, 276 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index bec42349e..b86b0870d 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -496,11 +496,12 @@ static int em28xx_audio_init(struct em28xx *dev)
struct snd_card *card;
#endif
static int devnr;
- int ret, err;
+ int err;
- if (dev->has_audio_class) {
+ if (dev->has_alsa_audio != 1) {
/* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module) */
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
return 0;
}
@@ -552,9 +553,10 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev == NULL)
return 0;
- if (dev->has_audio_class) {
+ if (dev->has_alsa_audio != 1) {
/* This device does not support the extension (in this case
- the device is expecting the snd-usb-audio module */
+ the device is expecting the snd-usb-audio module or
+ doesn't have analog audio support at all) */
return 0;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 4f078da31..d2967c434 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -59,7 +59,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2800_BOARD_UNKNOWN] = {
@@ -71,11 +71,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_UNKNOWN] = {
@@ -91,7 +91,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2820_BOARD_KWORLD_PVRTV2800RF] = {
@@ -104,11 +104,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
@@ -120,15 +120,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_PINNACLE_USB_2] = {
@@ -140,15 +140,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = {
@@ -183,15 +183,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_HERCULES_SMART_TV_USB2] = {
@@ -204,15 +204,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = {
@@ -226,15 +226,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_GADMEI_UTV310] = {
@@ -247,15 +247,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = {
@@ -268,15 +268,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = 2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = 9,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_PINNACLE_DVC_100] = {
@@ -287,11 +287,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
@@ -301,7 +301,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2821_BOARD_PROLINK_PLAYTV_USB2] = {
@@ -315,15 +315,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2821_BOARD_SUPERCOMP_USB_2] = {
@@ -339,15 +339,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2821_BOARD_USBGEAR_VD204] = {
@@ -358,11 +358,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2860_BOARD_NETGMBH_CAM] = {
@@ -373,7 +373,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = 0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2860_BOARD_TYPHOON_DVD_MAKER] = {
@@ -384,11 +384,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2860_BOARD_GADMEI_UTV330] = {
@@ -401,15 +401,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2860_BOARD_TERRATEC_HYBRID_XS] = {
@@ -421,15 +421,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2861_BOARD_KWORLD_PVRTV_300U] = {
@@ -441,15 +441,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2861_BOARD_YAKUMO_MOVIE_MIXER] = {
@@ -460,15 +460,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2861_BOARD_PLEXTOR_PX_TV100U] = {
@@ -481,15 +481,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2870_BOARD_TERRATEC_XS] = {
@@ -531,15 +531,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
@@ -553,15 +553,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = {
@@ -574,7 +574,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
@@ -582,7 +582,7 @@ struct em28xx_board em28xx_boards[] = {
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = {
@@ -593,19 +593,20 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_12mhz_i2s = 1,
.has_dvb = 1,
+ .ir_codes = ir_codes_hauppauge_new,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = {
@@ -616,19 +617,20 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_12mhz_i2s = 1,
.has_dvb = 1,
+ .ir_codes = ir_codes_pinnacle_pctv_hd,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = {
@@ -639,19 +641,20 @@ struct em28xx_board em28xx_boards[] = {
.mts_firmware = 1,
.has_12mhz_i2s = 1,
.has_dvb = 1,
+ .ir_codes = ir_codes_ati_tv_wonder_hd_600,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
@@ -664,15 +667,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
/* maybe there's a reason behind it why Terratec sells the Hybrid XS
@@ -687,15 +690,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_MSI_VOX_USB_2] = {
@@ -711,15 +714,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE4,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2800_BOARD_TERRATEC_CINERGY_200] = {
@@ -732,15 +735,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2800_BOARD_GRABBEEX_USB2800] = {
@@ -751,11 +754,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
@@ -768,15 +771,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2800_BOARD_KWORLD_USB2800] = {
@@ -789,15 +792,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_PINNACLE_DVC_90] = {
@@ -808,11 +811,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2800_BOARD_VGEAR_POCKETTV] = {
@@ -825,15 +828,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
@@ -866,7 +869,7 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
} },
},
[EM2880_BOARD_MSI_DIGIVOX_AD] = {
@@ -878,15 +881,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_MSI_DIGIVOX_AD_II] = {
@@ -898,15 +901,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_KWORLD_DVB_305U] = {
@@ -918,15 +921,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2880_BOARD_KWORLD_DVB_310U] = {
@@ -943,11 +946,11 @@ struct em28xx_board em28xx_boards[] = {
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = EM28XX_AMUX_AC97_LINE_IN,
+ .amux = EM28XX_AMUX_LINE_IN,
}, { /* S-video has not been tested yet */
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = EM28XX_AMUX_AC97_LINE_IN,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2881_BOARD_DNT_DA2_HYBRID] = {
@@ -959,15 +962,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
@@ -979,15 +982,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
@@ -1000,15 +1003,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2882_BOARD_KWORLD_VS_DVBT] = {
@@ -1020,15 +1023,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
@@ -1040,15 +1043,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2883_BOARD_KWORLD_HYBRID_A316] = {
@@ -1061,15 +1064,15 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
- .amux = 0,
+ .amux = EM28XX_AMUX_VIDEO,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
- .amux = 1,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = {
@@ -1088,6 +1091,21 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ [EM2874_BOARD_PINNACLE_PCTV_80E] = {
+ .name = "Pinnacle PCTV HD Mini",
+ .vchannels = 0,
+ .tuner_type = TUNER_ABSENT,
+ .has_dvb = 1,
+ .ir_codes = ir_codes_pinnacle_pctv_hd,
+ .decoder = EM28XX_NODECODER,
+#ifdef DJH_DEBUG
+ .input = { {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = TVP5150_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+#endif
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1185,6 +1203,8 @@ struct usb_device_id em28xx_id_table [] = {
.driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
+ { USB_DEVICE(0x2304, 0x023f),
+ .driver_info = EM2874_BOARD_PINNACLE_PCTV_80E },
{ USB_DEVICE(0x0413, 0x6023),
.driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
{ USB_DEVICE(0x093b, 0xa005),
@@ -1260,6 +1280,17 @@ static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = {
{ -1, -1, -1, -1},
};
+/* Pinnacle PCTV HD Mini (80e) GPIOs
+ 0-5: not used
+ 6: demod reset, active low
+ 7: LED on, active high */
+static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = {
+ {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/
+ {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/
+ {EM2874_R80_GPIO, 0xc0, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
/*
* EEPROM hash table for devices with generic USB IDs
*/
@@ -1307,6 +1338,7 @@ static void em28xx_set_model(struct em28xx *dev)
dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
dev->has_dvb = em28xx_boards[dev->model].has_dvb;
dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button;
+ dev->ir_codes = em28xx_boards[dev->model].ir_codes;
dev->valid = em28xx_boards[dev->model].valid;
}
@@ -1317,17 +1349,34 @@ void em28xx_pre_card_setup(struct em28xx *dev)
{
int rc;
- rc = em28xx_read_reg(dev, EM2880_R04_GPO);
- if (rc >= 0)
- dev->reg_gpo = rc;
+ /* Set the default GPO/GPIO for legacy devices */
+ dev->reg_gpo_num = EM2880_R04_GPO;
+ dev->reg_gpio_num = EM28XX_R08_GPIO;
dev->wait_after_write = 5;
+
+ /* Based on the Chip ID, set the device configuration */
rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
if (rc > 0) {
+ dev->chip_id = rc;
switch (rc) {
+ case CHIP_ID_EM2750:
+ em28xx_info("chip ID is em2750\n");
+ break;
+ case CHIP_ID_EM2820:
+ em28xx_info("chip ID is em2820\n");
+ break;
+ case CHIP_ID_EM2840:
+ em28xx_info("chip ID is em2840\n");
+ break;
case CHIP_ID_EM2860:
em28xx_info("chip ID is em2860\n");
break;
+ case CHIP_ID_EM2874:
+ em28xx_info("chip ID is em2874\n");
+ dev->reg_gpio_num = EM2874_R80_GPIO;
+ dev->wait_after_write = 0;
+ break;
case CHIP_ID_EM2883:
em28xx_info("chip ID is em2882/em2883\n");
dev->wait_after_write = 0;
@@ -1336,6 +1385,12 @@ void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_info("em28xx chip ID = %d\n", rc);
}
}
+
+ /* Prepopulate cached GPO register content */
+ rc = em28xx_read_reg(dev, dev->reg_gpo_num);
+ if (rc >= 0)
+ dev->reg_gpo = rc;
+
em28xx_set_model(dev);
/* request some modules */
@@ -1350,7 +1405,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2883_BOARD_KWORLD_HYBRID_A316:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(50);
/* Sets GPO/GPIO sequences for this device */
@@ -1362,7 +1419,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2882_BOARD_TERRATEC_HYBRID_XS:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(50);
/* should be added ir_codes here */
@@ -1382,7 +1441,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2870_BOARD_KWORLD_350U:
case EM2881_BOARD_DNT_DA2_HYBRID:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(50);
/* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital
@@ -1399,7 +1460,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2880_BOARD_MSI_DIGIVOX_AD:
case EM2880_BOARD_MSI_DIGIVOX_AD_II:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(50);
/* Sets GPO/GPIO sequences for this device */
@@ -1416,7 +1479,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2861_BOARD_PLEXTOR_PX_TV100U:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* FIXME guess */
/* Turn on analog audio output */
em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
@@ -1425,7 +1490,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2861_BOARD_KWORLD_PVRTV_300U:
case EM2880_BOARD_KWORLD_DVB_305U:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(10);
em28xx_write_regs(dev, 0x08, "\x6d", 1);
msleep(10);
@@ -1435,7 +1502,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2870_BOARD_KWORLD_355U:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
msleep(50);
/* Sets GPO/GPIO sequences for this device */
@@ -1444,7 +1513,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2870_BOARD_COMPRO_VIDEOMATE:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* TODO: someone can do some cleanup here...
not everything's needed */
em28xx_write_regs(dev, 0x04, "\x00", 1);
@@ -1463,7 +1534,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2870_BOARD_TERRATEC_XS_MT2060:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* this device needs some gpio writes to get the DVB-T
demod work */
em28xx_write_regs(dev, 0x08, "\xfe", 1);
@@ -1475,7 +1548,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
break;
case EM2870_BOARD_PINNACLE_PCTV_DVB:
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
+
/* this device needs some gpio writes to get the
DVB-T demod work */
em28xx_write_regs(dev, 0x08, "\xfe", 1);
@@ -1491,7 +1567,9 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2820_BOARD_GADMEI_UTV310:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* Turn on analog audio output */
em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
break;
@@ -1499,16 +1577,30 @@ void em28xx_pre_card_setup(struct em28xx *dev)
case EM2860_BOARD_GADMEI_UTV330:
/* Turn on IR */
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* should be added ir_codes here */
break;
case EM2820_BOARD_MSI_VOX_USB_2:
em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
- em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ);
/* enables audio for that device */
em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1);
break;
+
+ case EM2874_BOARD_PINNACLE_PCTV_80E:
+ /* Set 400 KHz clock and select secondary i2c bus */
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK,
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_FREQ_400_KHZ);
+
+ dev->digital_gpio = em2874_pinnacle_80e_digital;
+ break;
}
em28xx_gpio_set(dev, dev->tun_analog_gpio);
@@ -1717,6 +1809,7 @@ void em28xx_card_setup(struct em28xx *dev)
em28xx_set_model(dev);
dev->tuner_type = em28xx_boards[dev->model].tuner_type;
+ dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
/* request some modules */
switch (dev->model) {
@@ -1800,4 +1893,6 @@ void em28xx_card_setup(struct em28xx *dev)
#endif
em28xx_config_tuner(dev);
+
+ em28xx_ir_init(dev);
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 1a30e361c..dacb6cc5a 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -69,19 +69,33 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
int ret, byte;
if (dev->state & DEV_DISCONNECTED)
- return(-ENODEV);
+ return -ENODEV;
+
+ if (len > URB_MAX_CTRL_SIZE)
+ return -EINVAL;
em28xx_regdbg("req=%02x, reg=%02x ", req, reg);
+ mutex_lock(&dev->ctrl_urb_lock);
ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, buf, len, HZ);
+ 0x0000, reg, dev->urb_buf, len, HZ);
+ if (ret < 0) {
+ if (reg_debug)
+ printk(" failed!\n");
+ mutex_unlock(&dev->ctrl_urb_lock);
+ return ret;
+ }
+
+ if (len)
+ memcpy(buf, dev->urb_buf, len);
+
+ mutex_unlock(&dev->ctrl_urb_lock);
if (reg_debug) {
- printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
+ printk("%02x values: ", ret);
for (byte = 0; byte < len; byte++)
printk(" %02x", (unsigned char)buf[byte]);
-
printk("\n");
}
@@ -102,16 +116,20 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg)
em28xx_regdbg("req=%02x, reg=%02x:", req, reg);
+ mutex_lock(&dev->ctrl_urb_lock);
ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, &val, 1, HZ);
+ 0x0000, reg, dev->urb_buf, 1, HZ);
+ val = dev->urb_buf[0];
+ mutex_unlock(&dev->ctrl_urb_lock);
- if (reg_debug)
- printk(ret < 0 ? " failed!\n" :
- "%02x\n", (unsigned char) val);
-
- if (ret < 0)
+ if (ret < 0) {
+ printk(" failed!\n");
return ret;
+ }
+
+ if (reg_debug)
+ printk("%02x\n", (unsigned char) val);
return val;
}
@@ -130,19 +148,13 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
{
int ret;
- /*usb_control_msg seems to expect a kmalloced buffer */
- unsigned char *bufs;
-
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
- if (len < 1)
+ if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
return -EINVAL;
- bufs = kmalloc(len, GFP_KERNEL);
-
em28xx_regdbg("req=%02x reg=%02x:", req, reg);
-
if (reg_debug) {
int i;
for (i = 0; i < len; ++i)
@@ -150,16 +162,16 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
printk("\n");
}
- if (!bufs)
- return -ENOMEM;
- memcpy(bufs, buf, len);
+ mutex_lock(&dev->ctrl_urb_lock);
+ memcpy(dev->urb_buf, buf, len);
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, bufs, len, HZ);
+ 0x0000, reg, dev->urb_buf, len, HZ);
+ mutex_unlock(&dev->ctrl_urb_lock);
+
if (dev->wait_after_write)
msleep(dev->wait_after_write);
- kfree(bufs);
return ret;
}
@@ -175,15 +187,21 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
Not sure what happens on reading GPO register.
*/
if (rc >= 0) {
- if (reg == EM2880_R04_GPO)
+ if (reg == dev->reg_gpo_num)
dev->reg_gpo = buf[0];
- else if (reg == EM28XX_R08_GPIO)
+ else if (reg == dev->reg_gpio_num)
dev->reg_gpio = buf[0];
}
return rc;
}
+/* Write a single register */
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
+{
+ return em28xx_write_regs(dev, reg, &val, 1);
+}
+
/*
* em28xx_write_reg_bits()
* sets only some bits (specified by bitmask) of a register, by first reading
@@ -196,9 +214,9 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
u8 newval;
/* Uses cache for gpo/gpio registers */
- if (reg == EM2880_R04_GPO)
+ if (reg == dev->reg_gpo_num)
oldval = dev->reg_gpo;
- else if (reg == EM28XX_R08_GPIO)
+ else if (reg == dev->reg_gpio_num)
oldval = dev->reg_gpio;
else
oldval = em28xx_read_reg(dev, reg);
@@ -212,15 +230,70 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
}
/*
+ * em28xx_is_ac97_ready()
+ * Checks if ac97 is ready
+ */
+static int em28xx_is_ac97_ready(struct em28xx *dev)
+{
+ int ret, i;
+
+ /* Wait up to 50 ms for AC97 command to complete */
+ for (i = 0; i < 10; i++, msleep(5)) {
+ ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & 0x01))
+ return 0;
+ }
+
+ em28xx_warn("AC97 command still being executed: not handled properly!\n");
+ return -EBUSY;
+}
+
+/*
+ * em28xx_read_ac97()
+ * write a 16 bit value to the specified AC97 address (LSB first!)
+ */
+static int em28xx_read_ac97(struct em28xx *dev, u8 reg)
+{
+ int ret;
+ u8 addr = (reg & 0x7f) | 0x80;
+ u16 val;
+
+ ret = em28xx_is_ac97_ready(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R40_AC97LSB,
+ (u8 *)&val, sizeof(val));
+
+ if (ret < 0)
+ return ret;
+ return le16_to_cpu(val);
+}
+
+/*
* em28xx_write_ac97()
* write a 16 bit value to the specified AC97 address (LSB first!)
*/
-static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
+static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
{
- int ret, i;
+ int ret;
u8 addr = reg & 0x7f;
+ __le16 value;
+
+ value = cpu_to_le16(val);
+
+ ret = em28xx_is_ac97_ready(dev);
+ if (ret < 0)
+ return ret;
- ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
if (ret < 0)
return ret;
@@ -228,33 +301,59 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
if (ret < 0)
return ret;
- /* Wait up to 50 ms for AC97 command to complete */
- for (i = 0; i < 10; i++) {
- ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
- if (ret < 0)
- return ret;
+ return 0;
+}
- if (!(ret & 0x01))
- return 0;
- msleep(5);
+struct em28xx_input_table {
+ enum em28xx_amux amux;
+ u8 reg;
+};
+
+static struct em28xx_input_table inputs[] = {
+ { EM28XX_AMUX_VIDEO, AC97_VIDEO_VOL },
+ { EM28XX_AMUX_LINE_IN, AC97_LINEIN_VOL },
+ { EM28XX_AMUX_PHONE, AC97_PHONE_VOL },
+ { EM28XX_AMUX_MIC, AC97_MIC_VOL },
+ { EM28XX_AMUX_CD, AC97_CD_VOL },
+ { EM28XX_AMUX_AUX, AC97_AUX_VOL },
+ { EM28XX_AMUX_PCM_OUT, AC97_PCM_OUT_VOL },
+};
+
+static int set_ac97_input(struct em28xx *dev)
+{
+ int ret, i;
+ enum em28xx_amux amux = dev->ctl_ainput;
+
+ /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+ em28xx should point to LINE IN, while AC97 should use VIDEO
+ */
+ if (amux == EM28XX_AMUX_VIDEO2)
+ amux = dev->ctl_ainput;
+
+ /* Mute all entres but the one that were selected */
+ for (i = 0; i < ARRAY_SIZE(inputs); i++) {
+ if (amux == inputs[i].amux)
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x0808);
+ else
+ ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
+
+ if (ret < 0)
+ em28xx_warn("couldn't setup AC97 register %d\n",
+ inputs[i].reg);
}
- em28xx_warn("AC97 command still being executed: not handled properly!\n");
return 0;
}
static int em28xx_set_audio_source(struct em28xx *dev)
{
- static char *enable = "\x08\x08";
- static char *disable = "\x08\x88";
- char *video = enable, *line = disable;
int ret;
u8 input;
if (dev->is_em2800) {
- if (dev->ctl_ainput)
- input = EM2800_AUDIO_SRC_LINE;
- else
+ if (dev->ctl_ainput == EM28XX_AMUX_VIDEO)
input = EM2800_AUDIO_SRC_TUNER;
+ else
+ input = EM2800_AUDIO_SRC_LINE;
ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
if (ret < 0)
@@ -268,16 +367,8 @@ static int em28xx_set_audio_source(struct em28xx *dev)
case EM28XX_AMUX_VIDEO:
input = EM28XX_AUDIO_SRC_TUNER;
break;
- case EM28XX_AMUX_LINE_IN:
- input = EM28XX_AUDIO_SRC_LINE;
- break;
- case EM28XX_AMUX_AC97_VIDEO:
- input = EM28XX_AUDIO_SRC_LINE;
- break;
- case EM28XX_AMUX_AC97_LINE_IN:
+ default:
input = EM28XX_AUDIO_SRC_LINE;
- video = disable;
- line = enable;
break;
}
}
@@ -287,14 +378,12 @@ static int em28xx_set_audio_source(struct em28xx *dev)
return ret;
msleep(5);
- /* Sets AC97 mixer registers
- This is seems to be needed, even for non-ac97 configs
- */
- ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
+ switch (dev->audio_mode.ac97) {
+ case EM28XX_NO_AC97:
+ break;
+ default:
+ ret = set_ac97_input(dev);
+ }
return ret;
}
@@ -302,18 +391,21 @@ static int em28xx_set_audio_source(struct em28xx *dev)
int em28xx_audio_analog_set(struct em28xx *dev)
{
int ret;
- char s[2] = { 0x00, 0x00 };
u8 xclk = 0x07;
- s[0] |= 0x1f - dev->volume;
- s[1] |= 0x1f - dev->volume;
+ if (!dev->audio_mode.has_audio)
+ return 0;
- /* Mute */
- s[1] |= 0x80;
- ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
+ /* It is assumed that all devices use master volume for output.
+ It would be possible to use also line output.
+ */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ /* Mute */
+ ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, 0x8000);
- if (ret < 0)
- return ret;
+ if (ret < 0)
+ return ret;
+ }
if (dev->has_12mhz_i2s)
xclk |= 0x20;
@@ -329,15 +421,116 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Selects the proper audio input */
ret = em28xx_set_audio_source(dev);
- /* Unmute device */
- if (!dev->mute)
- s[1] &= ~0x80;
- ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
+ /* Sets volume */
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ int vol;
+
+ /* LSB: left channel - both channels with the same level */
+ vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8);
+
+ /* Mute device, if needed */
+ if (dev->mute)
+ vol |= 0x8000;
+
+ /* Sets volume */
+ ret = em28xx_write_ac97(dev, AC97_MASTER_VOL, vol);
+ }
return ret;
}
EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
+int em28xx_audio_setup(struct em28xx *dev)
+{
+ int vid1, vid2, feat, cfg;
+ u32 vid;
+
+ if (dev->chip_id == CHIP_ID_EM2874) {
+ /* Digital only device - don't load any alsa module */
+ dev->audio_mode.has_audio = 0;
+ dev->has_audio_class = 0;
+ dev->has_alsa_audio = 0;
+ return 0;
+ }
+
+ /* If device doesn't support Usb Audio Class, use vendor class */
+ if (!dev->has_audio_class)
+ dev->has_alsa_audio = 1;
+
+ dev->audio_mode.has_audio = 1;
+
+ /* See how this device is configured */
+ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
+ if (cfg < 0)
+ cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+ else
+ em28xx_info("Config register raw data: 0x%02x\n", cfg);
+
+ if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+ em28xx_info("I2S Audio (3 sample rates)\n");
+ dev->audio_mode.i2s_3rates = 1;
+ }
+ if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+ em28xx_info("I2S Audio (5 sample rates)\n");
+ dev->audio_mode.i2s_5rates = 1;
+ }
+
+ if (!(cfg & EM28XX_CHIPCFG_AC97)) {
+ dev->audio_mode.ac97 = EM28XX_NO_AC97;
+ goto init_audio;
+ }
+
+ dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
+
+ vid1 = em28xx_read_ac97(dev, AC97_VENDOR_ID1);
+ if (vid1 < 0) {
+ /* Device likely doesn't support AC97 */
+ em28xx_warn("AC97 chip type couldn't be determined\n");
+ goto init_audio;
+ }
+
+ vid2 = em28xx_read_ac97(dev, AC97_VENDOR_ID2);
+ if (vid2 < 0)
+ goto init_audio;
+
+ vid = vid1 << 16 | vid2;
+
+ dev->audio_mode.ac97_vendor_id = vid;
+ em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
+
+ feat = em28xx_read_ac97(dev, AC97_RESET);
+ if (feat < 0)
+ goto init_audio;
+
+ dev->audio_mode.ac97_feat = feat;
+ em28xx_warn("AC97 features = 0x%04x\n", feat);
+
+ /* Try to identify what audio processor we have */
+ if ((vid == 0xffffffff) && (feat == 0x6a90))
+ dev->audio_mode.ac97 = EM28XX_AC97_EM202;
+
+init_audio:
+ /* Reports detected AC97 processor */
+ switch (dev->audio_mode.ac97) {
+ case EM28XX_NO_AC97:
+ em28xx_info("No AC97 audio processor\n");
+ break;
+ case EM28XX_AC97_EM202:
+ em28xx_info("Empia 202 AC97 audio processor detected\n");
+ break;
+ case EM28XX_AC97_OTHER:
+ em28xx_warn("Unknown AC97 audio processor detected!\n");
+ break;
+ default:
+ break;
+ }
+
+ return em28xx_audio_analog_set(dev);
+}
+EXPORT_SYMBOL_GPL(em28xx_audio_setup);
+
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */
@@ -359,6 +552,24 @@ int em28xx_colorlevels_set_default(struct em28xx *dev)
int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
+
+ if (dev->chip_id == CHIP_ID_EM2874) {
+ /* The Transport Stream Enable Register moved in em2874 */
+ if (!start) {
+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+ 0x00,
+ EM2874_TS1_CAPTURE_ENABLE);
+ return rc;
+ }
+
+ /* Enable Transport Stream */
+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+ EM2874_TS1_CAPTURE_ENABLE,
+ EM2874_TS1_CAPTURE_ENABLE);
+ return rc;
+ }
+
+
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index 3bab56b99..ec3e3b157 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -332,14 +332,25 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
struct em28xx_eeprom *em_eeprom = (void *)eedata;
int i, err, size = len, block;
+ if (dev->chip_id == CHIP_ID_EM2874) {
+ /* Empia switched to a 16-bit addressable eeprom in newer
+ devices. While we could certainly write a routine to read
+ the eeprom, there is nothing of use in there that cannot be
+ accessed through registers, and there is the risk that we
+ could corrupt the eeprom (since a 16-bit read call is
+ interpreted as a write call by 8-bit eeproms).
+ */
+ return 0;
+ }
+
dev->i2c_client.addr = 0xa0 >> 1;
/* Check if board has eeprom */
err = i2c_master_recv(&dev->i2c_client, &buf, 0);
if (err < 0) {
- em28xx_errdev("%s: i2c_master_recv failed! err [%d]\n",
- __func__, err);
- return err;
+ em28xx_errdev("board has no eeprom\n");
+ memset(eedata, 0, len);
+ return -ENODEV;
}
buf = 0;
@@ -609,14 +620,16 @@ int em28xx_i2c_register(struct em28xx *dev)
dev->i2c_client.adapter = &dev->i2c_adap;
retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
- if (retval < 0) {
+ if ((retval < 0) && (retval != -ENODEV)) {
em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
__func__, retval);
+
return retval;
}
if (i2c_scan)
em28xx_do_i2c_scan(dev);
+
return 0;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 8d21eaad9..29900920d 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -39,12 +39,48 @@ static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-#define dprintk(fmt, arg...) \
+#define i2cdprintk(fmt, arg...) \
if (ir_debug) { \
printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
}
-/* ----------------------------------------------------------------------- */
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
+ }
+
+/**********************************************************
+ Polling structure used by em28xx IR's
+ **********************************************************/
+
+struct em28xx_ir_poll_result {
+ unsigned int toggle_bit:1;
+ unsigned int read_count:7;
+ u8 rc_address;
+ u8 rc_data[4]; /* 1 byte on em2860/2880, 4 on em2874 */
+};
+
+struct em28xx_IR {
+ struct em28xx *dev;
+ struct input_dev *input;
+ struct ir_input_state ir;
+ char name[32];
+ char phys[32];
+
+ /* poll external decoder */
+ int polling;
+ struct work_struct work;
+ struct timer_list timer;
+ unsigned int last_toggle:1;
+ unsigned int last_readcount;
+ unsigned int repeat_interval;
+
+ int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
+};
+
+/**********************************************************
+ I2C IR based get keycodes - should be used with ir-kbd-i2c
+ **********************************************************/
int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
@@ -52,7 +88,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
/* poll IR chip */
if (1 != i2c_master_recv(&ir->c, &b, 1)) {
- dprintk("read error\n");
+ i2cdprintk("read error\n");
return -EIO;
}
@@ -60,7 +96,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
down, while 0xff indicates that no button is hold
down. 0xfe sequences are sometimes interrupted by 0xFF */
- dprintk("key %02x\n", b);
+ i2cdprintk("key %02x\n", b);
if (b == 0xff)
return 0;
@@ -74,7 +110,6 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-
int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[2];
@@ -103,7 +138,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
((buf[0]&0x10)>>3) | /* 0000 0010 */
((buf[0]&0x20)>>5); /* 0000 0001 */
- dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+ i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
code, buf[0]);
/* return key */
@@ -120,11 +155,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */
if (3 != i2c_master_recv(&ir->c, buf, 3)) {
- dprintk("read error\n");
+ i2cdprintk("read error\n");
return -EIO;
}
- dprintk("key %02x\n", buf[2]&0x3f);
+ i2cdprintk("key %02x\n", buf[2]&0x3f);
if (buf[0] != 0x00)
return 0;
@@ -134,6 +169,276 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}
+/**********************************************************
+ Poll based get keycode functions
+ **********************************************************/
+
+/* This is for the em2860/em2880 */
+static int default_polling_getkey(struct em28xx_IR *ir,
+ struct em28xx_ir_poll_result *poll_result)
+{
+ struct em28xx *dev = ir->dev;
+ int rc;
+ u8 msg[3] = { 0, 0, 0 };
+
+ /* Read key toggle, brand, and key code
+ on registers 0x45, 0x46 and 0x47
+ */
+ rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR,
+ msg, sizeof(msg));
+ if (rc < 0)
+ return rc;
+
+ /* Infrared toggle (Reg 0x45[7]) */
+ poll_result->toggle_bit = (msg[0] >> 7);
+
+ /* Infrared read count (Reg 0x45[6:0] */
+ poll_result->read_count = (msg[0] & 0x7f);
+
+ /* Remote Control Address (Reg 0x46) */
+ poll_result->rc_address = msg[1];
+
+ /* Remote Control Data (Reg 0x47) */
+ poll_result->rc_data[0] = msg[2];
+
+ return 0;
+}
+
+static int em2874_polling_getkey(struct em28xx_IR *ir,
+ struct em28xx_ir_poll_result *poll_result)
+{
+ struct em28xx *dev = ir->dev;
+ int rc;
+ u8 msg[5] = { 0, 0, 0, 0, 0 };
+
+ /* Read key toggle, brand, and key code
+ on registers 0x51-55
+ */
+ rc = dev->em28xx_read_reg_req_len(dev, 0, EM2874_R51_IR,
+ msg, sizeof(msg));
+ if (rc < 0)
+ return rc;
+
+ /* Infrared toggle (Reg 0x51[7]) */
+ poll_result->toggle_bit = (msg[0] >> 7);
+
+ /* Infrared read count (Reg 0x51[6:0] */
+ poll_result->read_count = (msg[0] & 0x7f);
+
+ /* Remote Control Address (Reg 0x52) */
+ poll_result->rc_address = msg[1];
+
+ /* Remote Control Data (Reg 0x53-55) */
+ poll_result->rc_data[0] = msg[2];
+ poll_result->rc_data[1] = msg[3];
+ poll_result->rc_data[2] = msg[4];
+
+ return 0;
+}
+
+/**********************************************************
+ Polling code for em28xx
+ **********************************************************/
+
+static void em28xx_ir_handle_key(struct em28xx_IR *ir)
+{
+ int result;
+ int do_sendkey = 0;
+ struct em28xx_ir_poll_result poll_result;
+
+ /* read the registers containing the IR status */
+ result = ir->get_key(ir, &poll_result);
+ if (result < 0) {
+ dprintk("ir->get_key() failed %d\n", result);
+ return;
+ }
+
+ dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
+ poll_result.toggle_bit, poll_result.read_count,
+ ir->last_readcount, poll_result.rc_data[0]);
+
+ if (ir->dev->chip_id == CHIP_ID_EM2874) {
+ /* The em2874 clears the readcount field every time the
+ register is read. The em2860/2880 datasheet says that it
+ is supposed to clear the readcount, but it doesn't. So with
+ the em2874, we are looking for a non-zero read count as
+ opposed to a readcount that is incrementing */
+ ir->last_readcount = 0;
+ }
+
+ if (poll_result.read_count == 0) {
+ /* The button has not been pressed since the last read */
+ } else if (ir->last_toggle != poll_result.toggle_bit) {
+ /* A button has been pressed */
+ dprintk("button has been pressed\n");
+ ir->last_toggle = poll_result.toggle_bit;
+ ir->repeat_interval = 0;
+ do_sendkey = 1;
+ } else if (poll_result.toggle_bit == ir->last_toggle &&
+ poll_result.read_count > 0 &&
+ poll_result.read_count != ir->last_readcount) {
+ /* The button is still being held down */
+ dprintk("button being held down\n");
+
+ /* Debouncer for first keypress */
+ if (ir->repeat_interval++ > 9) {
+ /* Start repeating after 1 second */
+ do_sendkey = 1;
+ }
+ }
+
+ if (do_sendkey) {
+ dprintk("sending keypress\n");
+ ir_input_keydown(ir->input, &ir->ir, poll_result.rc_data[0],
+ poll_result.rc_data[0]);
+ ir_input_nokey(ir->input, &ir->ir);
+ }
+
+ ir->last_readcount = poll_result.read_count;
+ return;
+}
+
+static void ir_timer(unsigned long data)
+{
+ struct em28xx_IR *ir = (struct em28xx_IR *)data;
+
+ schedule_work(&ir->work);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void em28xx_ir_work(void *data)
+#else
+static void em28xx_ir_work(struct work_struct *work)
+#endif
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ struct em28xx_IR *ir = data;
+#else
+ struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work);
+#endif
+
+ em28xx_ir_handle_key(ir);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
+}
+
+void em28xx_ir_start(struct em28xx_IR *ir)
+{
+ setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&ir->work, em28xx_ir_work, ir);
+#else
+ INIT_WORK(&ir->work, em28xx_ir_work);
+#endif
+ schedule_work(&ir->work);
+}
+
+static void em28xx_ir_stop(struct em28xx_IR *ir)
+{
+ del_timer_sync(&ir->timer);
+ flush_scheduled_work();
+}
+
+int em28xx_ir_init(struct em28xx *dev)
+{
+ struct em28xx_IR *ir;
+ struct input_dev *input_dev;
+ u8 ir_config;
+ int err = -ENOMEM;
+
+ if (dev->ir_codes == NULL) {
+ /* No remote control support */
+ return 0;
+ }
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ir || !input_dev)
+ goto err_out_free;
+
+ ir->input = input_dev;
+
+ /* Setup the proper handler based on the chip */
+ switch (dev->chip_id) {
+ case CHIP_ID_EM2860:
+ case CHIP_ID_EM2883:
+ ir->get_key = default_polling_getkey;
+ break;
+ case CHIP_ID_EM2874:
+ ir->get_key = em2874_polling_getkey;
+ /* For now we only support RC5, so enable it */
+ ir_config = EM2874_IR_RC5;
+ em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1);
+ break;
+ default:
+ printk("Unrecognized em28xx chip id: IR not supported\n");
+ goto err_out_free;
+ }
+
+ /* This is how often we ask the chip for IR information */
+ ir->polling = 100; /* ms */
+
+ /* init input device */
+ snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)",
+ dev->name);
+
+ usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+ ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, dev->ir_codes);
+ input_dev->name = ir->name;
+ input_dev->phys = ir->phys;
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.version = 1;
+ input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
+ input_dev->dev.parent = &dev->udev->dev;
+#else
+ input_dev->cdev.dev = &dev->udev->dev;
+#endif
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+
+ em28xx_ir_start(ir);
+
+ /* all done */
+ err = input_register_device(ir->input);
+ if (err)
+ goto err_out_stop;
+
+ return 0;
+ err_out_stop:
+ em28xx_ir_stop(ir);
+ dev->ir = NULL;
+ err_out_free:
+ input_free_device(input_dev);
+ kfree(ir);
+ return err;
+}
+
+int em28xx_ir_fini(struct em28xx *dev)
+{
+ struct em28xx_IR *ir = dev->ir;
+
+ /* skip detach on non attached boards */
+ if (!ir)
+ return 0;
+
+ em28xx_ir_stop(ir);
+ input_unregister_device(ir->input);
+ kfree(ir);
+
+ /* done */
+ dev->ir = NULL;
+ return 0;
+}
+
+/**********************************************************
+ Handle Webcam snapshot button
+ **********************************************************/
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
static void em28xx_query_sbutton(void *data)
#else
@@ -232,9 +537,3 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
}
return;
}
-
-/* ----------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
index fac1ab23f..98e95054e 100644
--- a/linux/drivers/media/video/em28xx/em28xx-reg.h
+++ b/linux/drivers/media/video/em28xx/em28xx-reg.h
@@ -17,11 +17,34 @@
/* em28xx registers */
+#define EM28XX_R00_CHIPCFG 0x00
+
+/* em28xx Chip Configuration 0x00 */
+#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80
+#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
+#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x30
+#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x20
+#define EM28XX_CHIPCFG_AC97 0x10
+#define EM28XX_CHIPCFG_AUDIOMASK 0x30
+
/* GPIO/GPO registers */
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
#define EM28XX_R06_I2C_CLK 0x06
+
+/* em28xx I2C Clock Register (0x06) */
+#define EM28XX_I2C_CLK_ACK_LAST_READ 0x80
+#define EM28XX_I2C_CLK_WAIT_ENABLE 0x40
+#define EM28XX_I2C_EEPROM_ON_BOARD 0x08
+#define EM28XX_I2C_EEPROM_KEY_VALID 0x04
+#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */
+#define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */
+#define EM28XX_I2C_FREQ_25_KHZ 0x02
+#define EM28XX_I2C_FREQ_400_KHZ 0x01
+#define EM28XX_I2C_FREQ_100_KHZ 0x00
+
+
#define EM28XX_R0A_CHIPID 0x0a
#define EM28XX_R0C_USBSUSP 0x0c /* */
@@ -71,10 +94,32 @@
#define EM28XX_R42_AC97ADDR 0x42
#define EM28XX_R43_AC97BUSY 0x43
-/* em202 registers */
-#define EM28XX_R02_MASTER_AC97 0x02
-#define EM28XX_R10_LINE_IN_AC97 0x10
-#define EM28XX_R14_VIDEO_AC97 0x14
+#define EM28XX_R45_IR 0x45
+ /* 0x45 bit 7 - parity bit
+ bits 6-0 - count
+ 0x46 IR brand
+ 0x47 IR data
+ */
+
+/* em2874 registers */
+#define EM2874_R50_IR_CONFIG 0x50
+#define EM2874_R51_IR 0x51
+#define EM2874_R5F_TS_ENABLE 0x5f
+#define EM2874_R80_GPIO 0x80
+
+/* em2874 IR config register (0x50) */
+#define EM2874_IR_NEC 0x00
+#define EM2874_IR_RC5 0x04
+#define EM2874_IR_RC5_MODE_0 0x08
+#define EM2874_IR_RC5_MODE_6A 0x0b
+
+/* em2874 Transport Stream Enable Register (0x5f) */
+#define EM2874_TS1_CAPTURE_ENABLE (1 << 0)
+#define EM2874_TS1_FILTER_ENABLE (1 << 1)
+#define EM2874_TS1_NULL_DISCARD (1 << 2)
+#define EM2874_TS2_CAPTURE_ENABLE (1 << 4)
+#define EM2874_TS2_FILTER_ENABLE (1 << 5)
+#define EM2874_TS2_NULL_DISCARD (1 << 6)
/* register settings */
#define EM2800_AUDIO_SRC_TUNER 0x0d
@@ -84,6 +129,74 @@
/* FIXME: Need to be populated with the other chip ID's */
enum em28xx_chip_id {
+ CHIP_ID_EM2820 = 18,
+ CHIP_ID_EM2840 = 20,
+ CHIP_ID_EM2750 = 33,
CHIP_ID_EM2860 = 34,
CHIP_ID_EM2883 = 36,
+ CHIP_ID_EM2874 = 65,
};
+
+/*
+ * Registers used by em202 and other AC97 chips
+ */
+
+/* Standard AC97 registers */
+#define AC97_RESET 0x00
+
+ /* Output volumes */
+#define AC97_MASTER_VOL 0x02
+#define AC97_LINE_LEVEL_VOL 0x04 /* Some devices use for headphones */
+#define AC97_MASTER_MONO_VOL 0x06
+
+ /* Input volumes */
+#define AC97_PC_BEEP_VOL 0x0a
+#define AC97_PHONE_VOL 0x0c
+#define AC97_MIC_VOL 0x0e
+#define AC97_LINEIN_VOL 0x10
+#define AC97_CD_VOL 0x12
+#define AC97_VIDEO_VOL 0x14
+#define AC97_AUX_VOL 0x16
+#define AC97_PCM_OUT_VOL 0x18
+
+ /* capture registers */
+#define AC97_RECORD_SELECT 0x1a
+#define AC97_RECORD_GAIN 0x1c
+
+ /* control registers */
+#define AC97_GENERAL_PURPOSE 0x20
+#define AC97_3D_CTRL 0x22
+#define AC97_AUD_INT_AND_PAG 0x24
+#define AC97_POWER_DOWN_CTRL 0x26
+#define AC97_EXT_AUD_ID 0x28
+#define AC97_EXT_AUD_CTRL 0x2a
+
+/* Supported rate varies for each AC97 device
+ if write an unsupported value, it will return the closest one
+ */
+#define AC97_PCM_OUT_FRONT_SRATE 0x2c
+#define AC97_PCM_OUT_SURR_SRATE 0x2e
+#define AC97_PCM_OUT_LFE_SRATE 0x30
+#define AC97_PCM_IN_SRATE 0x32
+
+ /* For devices with more than 2 channels, extra output volumes */
+#define AC97_LFE_MASTER_VOL 0x36
+#define AC97_SURR_MASTER_VOL 0x38
+
+ /* Digital SPDIF output control */
+#define AC97_SPDIF_OUT_CTRL 0x3a
+
+ /* Vendor ID identifier */
+#define AC97_VENDOR_ID1 0x7c
+#define AC97_VENDOR_ID2 0x7e
+
+/* EMP202 vendor registers */
+#define EM202_EXT_MODEM_CTRL 0x3e
+#define EM202_GPIO_CONF 0x4c
+#define EM202_GPIO_POLARITY 0x4e
+#define EM202_GPIO_STICKY 0x50
+#define EM202_GPIO_MASK 0x52
+#define EM202_GPIO_STATUS 0x54
+#define EM202_SPDIF_OUT_SEL 0x6a
+#define EM202_ANTIPOP 0x72
+#define EM202_EAPD_GPIO_ACCESS 0x74
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index a4493da8a..88bff6bd7 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -1656,11 +1656,13 @@ static void em28xx_release_resources(struct em28xx *dev)
/*FIXME: I2C IR should be disconnected */
- em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
- dev->vdev->num, dev->vbi_dev->num);
list_del(&dev->devlist);
if (dev->sbutton_input_dev)
em28xx_deregister_snapshot_button(dev);
+
+ if (dev->ir)
+ em28xx_ir_fini(dev);
+
if (dev->radio_dev) {
if (-1 != dev->radio_dev->minor)
video_unregister_device(dev->radio_dev);
@@ -1669,6 +1671,8 @@ static void em28xx_release_resources(struct em28xx *dev)
dev->radio_dev = NULL;
}
if (dev->vbi_dev) {
+ em28xx_info("V4L2 device /dev/vbi%d deregistered\n",
+ dev->vbi_dev->num);
if (-1 != dev->vbi_dev->minor)
video_unregister_device(dev->vbi_dev);
else
@@ -1676,6 +1680,8 @@ static void em28xx_release_resources(struct em28xx *dev)
dev->vbi_dev = NULL;
}
if (dev->vdev) {
+ em28xx_info("V4L2 device /dev/video%d deregistered\n",
+ dev->vdev->num);
if (-1 != dev->vdev->minor)
video_unregister_device(dev->vdev);
else
@@ -1982,7 +1988,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return vfd;
}
-
/*
* em28xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
@@ -1998,6 +2003,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->udev = udev;
mutex_init(&dev->lock);
+ mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
init_waitqueue_head(&dev->open);
init_waitqueue_head(&dev->wait_frame);
@@ -2015,8 +2021,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
errCode = em28xx_config(dev);
if (errCode) {
em28xx_errdev("error configuring device\n");
- em28xx_devused &= ~(1<<dev->devno);
- kfree(dev);
return -ENOMEM;
}
@@ -2032,11 +2036,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
em28xx_card_setup(dev);
/* Configure audio */
- errCode = em28xx_audio_analog_set(dev);
+ errCode = em28xx_audio_setup(dev);
if (errCode < 0) {
- em28xx_errdev("%s: em28xx_audio_analog_set - errCode [%d]!\n",
+ em28xx_errdev("%s: Error while setting audio - errCode [%d]!\n",
__func__, errCode);
- return errCode;
}
/* configure the device */
@@ -2153,7 +2156,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
fail_unreg:
em28xx_release_resources(dev);
mutex_unlock(&dev->lock);
- kfree(dev);
return retval;
}
@@ -2171,7 +2173,7 @@ static void request_module_async(struct work_struct *work)
if (dev->has_audio_class)
request_module("snd-usb-audio");
- else
+ else if (dev->has_alsa_audio)
request_module("em28xx-alsa");
if (dev->has_dvb)
@@ -2204,7 +2206,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
struct usb_interface *uif;
struct em28xx *dev = NULL;
int retval = -ENODEV;
- int i, nr, ifnum;
+ int i, nr, ifnum, isoc_pipe;
udev = usb_get_dev(interface_to_usbdev(interface));
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
@@ -2231,19 +2233,29 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
- endpoint = &interface->cur_altsetting->endpoint[1].desc;
+ endpoint = &interface->cur_altsetting->endpoint[0].desc;
/* check if the device has the iso in endpoint at the correct place */
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
- USB_ENDPOINT_XFER_ISOC) {
- em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
- em28xx_devused &= ~(1<<nr);
- return -ENODEV;
- }
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
- em28xx_devused &= ~(1<<nr);
- return -ENODEV;
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC &&
+ (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940))
+ {
+ /* It's a newer em2874/em2875 device */
+ isoc_pipe = 0;
+ } else {
+ isoc_pipe = 1;
+ endpoint = &interface->cur_altsetting->endpoint[1].desc;
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
+ em28xx_devused &= ~(1<<nr);
+ return -ENODEV;
+ }
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
+ em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
+ em28xx_devused &= ~(1<<nr);
+ return -ENODEV;
+ }
}
if (nr >= EM28XX_MAXBOARDS) {
@@ -2275,9 +2287,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
}
- printk(KERN_INFO DRIVER_NAME " %s usb audio class\n",
- dev->has_audio_class ? "Has" : "Doesn't have");
-
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
@@ -2294,7 +2303,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
}
for (i = 0; i < dev->num_alt ; i++) {
- u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
wMaxPacketSize);
dev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
@@ -2307,8 +2316,12 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* allocate device struct */
retval = em28xx_init_dev(&dev, udev, nr);
- if (retval)
+ if (retval) {
+ em28xx_devused &= ~(1<<dev->devno);
+ kfree(dev);
+
return retval;
+ }
em28xx_info("Found %s\n", em28xx_boards[dev->model].name);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index d73b8c983..9f96128df 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -98,11 +98,15 @@
#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56
#define EM2883_BOARD_KWORLD_HYBRID_A316 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
+#define EM2874_BOARD_PINNACLE_PCTV_80E 59
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
#define EM28XX_DEF_BUF 8
+/*Limits the max URB message size */
+#define URB_MAX_CTRL_SIZE 80
+
/* Params for validated field */
#define EM28XX_BOARD_NOT_VALIDATED 1
#define EM28XX_BOARD_VALIDATED 0
@@ -253,11 +257,43 @@ enum enum28xx_itype {
EM28XX_RADIO,
};
+enum em28xx_ac97_mode {
+ EM28XX_NO_AC97 = 0,
+ EM28XX_AC97_EM202,
+ EM28XX_AC97_OTHER,
+};
+
+struct em28xx_audio_mode {
+ enum em28xx_ac97_mode ac97;
+
+ u16 ac97_feat;
+ u32 ac97_vendor_id;
+
+ unsigned int has_audio:1;
+
+ unsigned int i2s_3rates:1;
+ unsigned int i2s_5rates:1;
+};
+
+/* em28xx has two audio inputs: tuner and line in.
+ However, on most devices, an auxiliary AC97 codec device is used.
+ The AC97 device may have several different inputs and outputs,
+ depending on their model. So, it is possible to use AC97 mixer to
+ address more than two different entries.
+ */
enum em28xx_amux {
- EM28XX_AMUX_VIDEO,
- EM28XX_AMUX_LINE_IN,
- EM28XX_AMUX_AC97_VIDEO,
- EM28XX_AMUX_AC97_LINE_IN,
+ /* This is the only entry for em28xx tuner input */
+ EM28XX_AMUX_VIDEO, /* em28xx tuner, AC97 mixer Video */
+
+ EM28XX_AMUX_LINE_IN, /* AC97 mixer Line In */
+
+ /* Some less-common mixer setups */
+ EM28XX_AMUX_VIDEO2, /* em28xx Line in, AC97 mixer Video */
+ EM28XX_AMUX_PHONE,
+ EM28XX_AMUX_MIC,
+ EM28XX_AMUX_CD,
+ EM28XX_AMUX_AUX,
+ EM28XX_AMUX_PCM_OUT,
};
struct em28xx_input {
@@ -269,6 +305,7 @@ struct em28xx_input {
#define INPUT(nr) (&em28xx_boards[dev->model].input[nr])
enum em28xx_decoder {
+ EM28XX_NODECODER,
EM28XX_TVP5150,
EM28XX_SAA7113,
EM28XX_SAA7114
@@ -284,6 +321,7 @@ struct em28xx_board {
char *name;
int vchannels;
int tuner_type;
+ int tuner_addr;
/* i2c flags */
unsigned int tda9887_conf;
@@ -301,6 +339,7 @@ struct em28xx_board {
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
+ IR_KEYTAB_TYPE *ir_codes;
};
struct em28xx_eeprom {
@@ -375,17 +414,21 @@ struct em28xx {
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
+ enum em28xx_chip_id chip_id;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
unsigned int stream_on:1; /* Locks streams */
unsigned int has_audio_class:1;
+ unsigned int has_alsa_audio:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
unsigned int has_snapshot_button:1;
unsigned int valid:1; /* report for validated boards */
+ struct em28xx_IR *ir;
+
/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;
@@ -401,6 +444,7 @@ struct em28xx {
u32 i2s_speed; /* I2S speed for audio digital stream */
enum em28xx_decoder decoder;
+ struct em28xx_audio_mode audio_mode;
int tuner_type; /* type of the tuner */
int tuner_addr; /* tuner address */
@@ -439,6 +483,7 @@ struct em28xx {
/* locks */
struct mutex lock;
+ struct mutex ctrl_urb_lock; /* protects urb_buf */
/* spinlock_t queue_lock; */
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
@@ -460,6 +505,8 @@ struct em28xx {
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
+ char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
+
/* helper funcs that call usb_control_msg */
int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
char *buf, int len);
@@ -472,9 +519,15 @@ struct em28xx {
enum em28xx_mode mode;
+ /* register numbers for GPO/GPIO registers */
+ u16 reg_gpo_num, reg_gpio_num;
+
/* Caches GPO and GPIO registers */
unsigned char reg_gpo, reg_gpio;
+ /* Infrared remote control support */
+ IR_KEYTAB_TYPE *ir_codes;
+
/* Snapshot button */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
@@ -515,7 +568,10 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg);
int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int len);
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
+int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
+
int em28xx_audio_analog_set(struct em28xx *dev);
+int em28xx_audio_setup(struct em28xx *dev);
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
@@ -544,7 +600,6 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
/* Provided by em28xx-input.c */
-/* TODO: Check if the standard get_key handlers on ir-common can be used */
int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
@@ -552,6 +607,9 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
void em28xx_register_snapshot_button(struct em28xx *dev);
void em28xx_deregister_snapshot_button(struct em28xx *dev);
+int em28xx_ir_init(struct em28xx *dev);
+int em28xx_ir_fini(struct em28xx *dev);
+
/* printk macros */
#define em28xx_err(fmt, arg...) do {\