Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (425 commits)
  V4L/DVB (11870): gspca - main: VIDIOC_ENUM_FRAMESIZES ioctl added.
  V4L/DVB (12004): poll method lose race condition
  V4L/DVB (11894): flexcop-pci: dmesg visible names broken
  V4L/DVB (11892): Siano: smsendian - declare function as extern
  V4L/DVB (11891): Siano: smscore - bind the GPIO SMS protocol
  V4L/DVB (11890): Siano: smscore - remove redundant code
  V4L/DVB (11889): Siano: smsdvb - add DVB v3 events
  V4L/DVB (11888): Siano: smsusb - remove redundant ifdef
  V4L/DVB (11887): Siano: smscards - add board (target) events
  V4L/DVB (11886): Siano: smscore - fix some new GPIO definitions names
  V4L/DVB (11885): Siano: Add new GPIO management interface
  V4L/DVB (11884): Siano: smssdio - revert to stand alone module
  V4L/DVB (11883): Siano: cards - add two additional (USB) devices
  V4L/DVB (11824): Siano: smsusb - change exit func debug msg
  V4L/DVB (11823): Siano: smsusb - fix typo in module description
  V4L/DVB (11822): Siano: smscore - bug fix at get_device_mode
  V4L/DVB (11821): Siano: smscore - fix isdb-t firmware name
  V4L/DVB (11820): Siano: smscore - fix byte ordering bug
  V4L/DVB (11819): Siano: smscore - fix get_common_buffer bug
  V4L/DVB (11818): Siano: smscards - assign gpio to HPG targets
  ...
This commit is contained in:
Linus Torvalds 2009-06-16 21:15:42 -07:00
commit 0dd5198672
254 changed files with 21943 additions and 6654 deletions

View file

@ -112,7 +112,7 @@ sub tda10045 {
sub tda10046 {
my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
my $url = "http://technotrend-online.com/download/software/219/$sourcefile";
my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
my $hash = "6a7e1e2f2644b162ff0502367553c72d";
my $outfile = "dvb-fe-tda10046.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@ -129,8 +129,8 @@ sub tda10046 {
}
sub tda10046lifeview {
my $sourcefile = "Drv_2.11.02.zip";
my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
my $sourcefile = "7%5Cdrv_2.11.02.zip";
my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile";
my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
my $outfile = "dvb-fe-tda10046.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@ -317,7 +317,7 @@ sub nxt2002 {
sub nxt2004 {
my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
my $url = "http://www.aver.com/support/Drivers/$sourcefile";
my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
my $hash = "111cb885b1e009188346d72acfed024c";
my $outfile = "dvb-fe-nxt2004.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

View file

@ -16,3 +16,8 @@
15 -> TeVii S470 [d470:9022]
16 -> DVBWorld DVB-S2 2005 [0001:2005]
17 -> NetUP Dual DVB-S2 CI [1b55:2a2c]
18 -> Hauppauge WinTV-HVR1270 [0070:2211]
19 -> Hauppauge WinTV-HVR1275 [0070:2215]
20 -> Hauppauge WinTV-HVR1255 [0070:2251]
21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295]
22 -> Mygica X8506 DMB-TH [14f1:8651]

View file

@ -78,3 +78,5 @@
77 -> TBS 8910 DVB-S [8910:8888]
78 -> Prof 6200 DVB-S [b022:3022]
79 -> Terratec Cinergy HT PCI MKII [153b:1177]
80 -> Hauppauge WinTV-IR Only [0070:9290]
81 -> Leadtek WinFast DTV1800 Hybrid [107d:6654]

View file

@ -17,7 +17,7 @@
16 -> Hauppauge WinTV HVR 950 (em2883) [2040:6513,2040:6517,2040:651b]
17 -> Pinnacle PCTV HD Pro Stick (em2880) [2304:0227]
18 -> Hauppauge WinTV HVR 900 (R2) (em2880) [2040:6502]
19 -> PointNix Intra-Oral Camera (em2860)
19 -> EM2860/SAA711X Reference Design (em2860)
20 -> AMD ATI TV Wonder HD 600 (em2880) [0438:b002]
21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800) [eb1a:2801]
22 -> Unknown EM2750/EM2751 webcam grabber (em2750) [eb1a:2750,eb1a:2751]
@ -61,3 +61,7 @@
63 -> Kaiomy TVnPC U2 (em2860) [eb1a:e303]
64 -> Easy Cap Capture DC-60 (em2860)
65 -> IO-DATA GV-MVP/SZ (em2820/em2840) [04bb:0515]
66 -> Empire dual TV (em2880)
67 -> Terratec Grabby (em2860) [0ccd:0096]
68 -> Terratec AV350 (em2860) [0ccd:0084]
69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313]

View file

@ -124,10 +124,10 @@
123 -> Beholder BeholdTV 407 [0000:4070]
124 -> Beholder BeholdTV 407 FM [0000:4071]
125 -> Beholder BeholdTV 409 [0000:4090]
126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050]
127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
126 -> Beholder BeholdTV 505 FM [5ace:5050]
127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
128 -> Beholder BeholdTV Columbus TVFM [0000:5201]
129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
129 -> Beholder BeholdTV 607 FM [5ace:6070]
130 -> Beholder BeholdTV M6 [5ace:6190]
131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022]
132 -> Genius TVGO AM11MCE
@ -143,7 +143,7 @@
142 -> Beholder BeholdTV H6 [5ace:6290]
143 -> Beholder BeholdTV M63 [5ace:6191]
144 -> Beholder BeholdTV M6 Extra [5ace:6193]
145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636]
145 -> AVerMedia MiniPCI DVB-T Hybrid M103 [1461:f636,1461:f736]
146 -> ASUSTeK P7131 Analog
147 -> Asus Tiger 3in1 [1043:4878]
148 -> Encore ENLTV-FM v5.3 [1a7f:2008]
@ -154,4 +154,16 @@
153 -> Kworld Plus TV Analog Lite PCI [17de:7128]
154 -> Avermedia AVerTV GO 007 FM Plus [1461:f31d]
155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid [0070:6706,0070:6708]
156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a]
156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid [0070:6707,0070:6709,0070:670a]
157 -> Avermedia AVerTV Studio 507UA [1461:a11b]
158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9]
159 -> Beholder BeholdTV 505 RDS [0000:505B]
160 -> Beholder BeholdTV 507 RDS [0000:5071]
161 -> Beholder BeholdTV 507 RDS [0000:507B]
162 -> Beholder BeholdTV 607 FM [5ace:6071]
163 -> Beholder BeholdTV 609 FM [5ace:6090]
164 -> Beholder BeholdTV 609 FM [5ace:6091]
165 -> Beholder BeholdTV 607 RDS [5ace:6072]
166 -> Beholder BeholdTV 607 RDS [5ace:6073]
167 -> Beholder BeholdTV 609 RDS [5ace:6092]
168 -> Beholder BeholdTV 609 RDS [5ace:6093]

View file

@ -76,3 +76,5 @@ tuner=75 - Philips TEA5761 FM Radio
tuner=76 - Xceive 5000 tuner
tuner=77 - TCL tuner MF02GIP-5N-E
tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough

View file

@ -163,10 +163,11 @@ sunplus 055f:c650 Mustek MDC5500Z
zc3xx 055f:d003 Mustek WCam300A
zc3xx 055f:d004 Mustek WCam300 AN
conex 0572:0041 Creative Notebook cx11646
ov519 05a9:0519 OmniVision
ov519 05a9:0519 OV519 Microphone
ov519 05a9:0530 OmniVision
ov519 05a9:4519 OmniVision
ov519 05a9:4519 Webcam Classic
ov519 05a9:8519 OmniVision
ov519 05a9:a518 D-Link DSB-C310 Webcam
sunplus 05da:1018 Digital Dream Enigma 1.3
stk014 05e1:0893 Syntek DV4000
spca561 060b:a001 Maxell Compact Pc PM3
@ -178,6 +179,7 @@ spca506 06e1:a190 ADS Instant VCD
ov534 06f8:3002 Hercules Blog Webcam
ov534 06f8:3003 Hercules Dualpix HD Weblog
sonixj 06f8:3004 Hercules Classic Silver
sonixj 06f8:3008 Hercules Deluxe Optical Glass
spca508 0733:0110 ViewQuest VQ110
spca508 0130:0130 Clone Digital Webcam 11043
spca501 0733:0401 Intel Create and Share
@ -209,6 +211,7 @@ sunplus 08ca:2050 Medion MD 41437
sunplus 08ca:2060 Aiptek PocketDV5300
tv8532 0923:010f ICM532 cams
mars 093a:050f Mars-Semi Pc-Camera
mr97310a 093a:010f Sakar Digital no. 77379
pac207 093a:2460 Qtec Webcam 100
pac207 093a:2461 HP Webcam
pac207 093a:2463 Philips SPC 220 NC
@ -265,6 +268,11 @@ sonixj 0c45:60ec SN9C105+MO4000
sonixj 0c45:60fb Surfer NoName
sonixj 0c45:60fc LG-LIC300
sonixj 0c45:60fe Microdia Audio
sonixj 0c45:6100 PC Camera (SN9C128)
sonixj 0c45:610a PC Camera (SN9C128)
sonixj 0c45:610b PC Camera (SN9C128)
sonixj 0c45:610c PC Camera (SN9C128)
sonixj 0c45:610e PC Camera (SN9C128)
sonixj 0c45:6128 Microdia/Sonix SNP325
sonixj 0c45:612a Avant Camera
sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix

View file

@ -26,6 +26,55 @@ Global video workflow
Once the last buffer is filled in, the QCI interface stops.
c) Capture global finite state machine schema
+----+ +---+ +----+
| DQ | | Q | | DQ |
| v | v | v
+-----------+ +------------------------+
| STOP | | Wait for capture start |
+-----------+ Q +------------------------+
+-> | QCI: stop | ------------------> | QCI: run | <------------+
| | DMA: stop | | DMA: stop | |
| +-----------+ +-----> +------------------------+ |
| / | |
| / +---+ +----+ | |
|capture list empty / | Q | | DQ | | QCI Irq EOF |
| / | v | v v |
| +--------------------+ +----------------------+ |
| | DMA hotlink missed | | Capture running | |
| +--------------------+ +----------------------+ |
| | QCI: run | +-----> | QCI: run | <-+ |
| | DMA: stop | / | DMA: run | | |
| +--------------------+ / +----------------------+ | Other |
| ^ /DMA still | | channels |
| | capture list / running | DMA Irq End | not |
| | not empty / | | finished |
| | / v | yet |
| +----------------------+ +----------------------+ | |
| | Videobuf released | | Channel completed | | |
| +----------------------+ +----------------------+ | |
+-- | QCI: run | | QCI: run | --+ |
| DMA: run | | DMA: run | |
+----------------------+ +----------------------+ |
^ / | |
| no overrun / | overrun |
| / v |
+--------------------+ / +----------------------+ |
| Frame completed | / | Frame overran | |
+--------------------+ <-----+ +----------------------+ restart frame |
| QCI: run | | QCI: stop | --------------+
| DMA: run | | DMA: stop |
+--------------------+ +----------------------+
Legend: - each box is a FSM state
- each arrow is the condition to transition to another state
- an arrow with a comment is a mandatory transition (no condition)
- arrow "Q" means : a buffer was enqueued
- arrow "DQ" means : a buffer was dequeued
- "QCI: stop" means the QCI interface is not enabled
- "DMA: stop" means all 3 DMA channels are stopped
- "DMA: run" means at least 1 DMA channel is still running
DMA usage
---------

View file

@ -89,6 +89,11 @@ from dev (driver name followed by the bus_id, to be precise). If you set it
up before calling v4l2_device_register then it will be untouched. If dev is
NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
You can use v4l2_device_set_name() to set the name based on a driver name and
a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
etc. If the name ends with a digit, then it will insert a dash: cx18-0,
cx18-1, etc. This function returns the instance number.
The first 'dev' argument is normally the struct device pointer of a pci_dev,
usb_interface or platform_device. It is rare for dev to be NULL, but it happens
with ISA devices or when one device creates multiple PCI devices, thus making

View file

@ -380,12 +380,12 @@ static struct pca953x_platform_data pca9536_data = {
.gpio_base = NR_BUILTIN_GPIO,
};
static int gpio_bus_switch;
static int gpio_bus_switch = -EINVAL;
static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
unsigned long flags)
unsigned long flags)
{
if (gpio_bus_switch <= 0) {
if (gpio_bus_switch < 0) {
if (flags == SOCAM_DATAWIDTH_10)
return 0;
else
@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
{
int ret;
if (!gpio_bus_switch) {
if (gpio_bus_switch < 0) {
ret = gpio_request(NR_BUILTIN_GPIO, "camera");
if (!ret) {
gpio_bus_switch = NR_BUILTIN_GPIO;
gpio_direction_output(gpio_bus_switch, 0);
} else
gpio_bus_switch = -EINVAL;
}
}
if (gpio_bus_switch > 0)
if (gpio_bus_switch >= 0)
return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
else
return SOCAM_DATAWIDTH_10;
}
static void pcm990_camera_free_bus(struct soc_camera_link *link)
{
if (gpio_bus_switch < 0)
return;
gpio_free(gpio_bus_switch);
gpio_bus_switch = -EINVAL;
}
static struct soc_camera_link iclink = {
.bus_id = 0, /* Must match with the camera ID above */
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
};
/* Board I2C devices. */

View file

@ -2,8 +2,14 @@
# Multimedia device configuration
#
menu "Multimedia devices"
menuconfig MEDIA_SUPPORT
tristate "Multimedia support"
depends on HAS_IOMEM
help
If you want to use Video for Linux, DVB for Linux, or DAB adapters,
enable this option and other options below.
if MEDIA_SUPPORT
comment "Multimedia core support"
@ -136,4 +142,4 @@ config USB_DABUSB
module will be called dabusb.
endif # DAB
endmenu
endif # MEDIA_SUPPORT

View file

@ -416,6 +416,24 @@ static int simple_std_setup(struct dvb_frontend *fe,
return 0;
}
static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
int rc;
u8 buffer[2];
buffer[0] = (config & ~0x38) | 0x18;
buffer[1] = aux;
tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
if (2 != rc)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
return rc == 2 ? 0 : rc;
}
static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
u16 div, u8 config, u8 cb)
{
@ -424,17 +442,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
switch (priv->type) {
case TUNER_LG_TDVS_H06XF:
/* Set the Auxiliary Byte. */
buffer[0] = buffer[2];
buffer[0] &= ~0x20;
buffer[0] |= 0x18;
buffer[1] = 0x20;
tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
if (2 != rc)
tuner_warn("i2c i/o error: rc == %d "
"(should be 2)\n", rc);
simple_set_aux_byte(fe, config, 0x20);
break;
case TUNER_PHILIPS_FQ1216LME_MK3:
simple_set_aux_byte(fe, config, 0x60); /* External AGC */
break;
case TUNER_MICROTUNE_4042FI5:
{
@ -506,6 +517,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_THOMSON_DTT761X:
buffer[3] = 0x39;
break;
case TUNER_PHILIPS_FQ1216LME_MK3:
tuner_err("This tuner doesn't have FM\n");
/* Set the low band for sanity, since it covers 88-108 MHz */
buffer[3] = 0x01;
break;
case TUNER_MICROTUNE_4049FM5:
default:
buffer[3] = 0xa4;
@ -678,12 +694,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
return 0;
}
/* Bandswitch byte */
simple_radio_bandswitch(fe, &buffer[0]);
buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
TUNER_RATIO_SELECT_50; /* 50 kHz step */
/* Bandswitch byte */
simple_radio_bandswitch(fe, &buffer[0]);
/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
freq * (1/800) */

View file

@ -578,6 +578,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
},
};
/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
{ 16 * 158.00 /*MHz*/, 0xce, 0x01, },
{ 16 * 441.00 /*MHz*/, 0xce, 0x02, },
{ 16 * 864.00 , 0xce, 0x04, },
};
static struct tuner_params tuner_fm1216mk5_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_fm1216mk5_pal_ranges,
.count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
.cb_first_if_lower_freq = 1,
.has_tda9887 = 1,
.port1_active = 1,
.port2_active = 1,
.port2_invert_for_secam_lc = 1,
.port1_fm_high_sensitivity = 1,
.default_top_mid = -2,
.default_top_secam_mid = -2,
.default_top_secam_high = -2,
},
};
/* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
@ -1254,6 +1279,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
},
};
/* 80-89 */
/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
static struct tuner_params tuner_fq1216lme_mk3_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_fm1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
.cb_first_if_lower_freq = 1, /* not specified, but safe to do */
.has_tda9887 = 1, /* TDA9886 */
.port1_active = 1,
.port2_active = 1,
.port2_invert_for_secam_lc = 1,
.default_top_low = 4,
.default_top_mid = 4,
.default_top_high = 4,
.default_top_secam_low = 4,
.default_top_secam_mid = 4,
.default_top_secam_high = 4,
},
};
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@ -1694,6 +1741,18 @@ struct tunertype tuners[] = {
.initdata = tua603x_agc112,
.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
},
[TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
.name = "Philips PAL/SECAM multi (FM1216 MK5)",
.params = tuner_fm1216mk5_params,
.count = ARRAY_SIZE(tuner_fm1216mk5_params),
},
/* 80-89 */
[TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
.name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
.params = tuner_fq1216lme_mk3_params,
.count = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
},
};
EXPORT_SYMBOL(tuners);

View file

@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages");
static int no_poweroff;
module_param(no_poweroff, int, 0644);
MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
"1 keep device energized and with tuner ready all the times.\n"
" Faster, but consumes more power and keeps the device hotter\n");
@ -272,7 +272,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
fname = firmware_name;
tuner_dbg("Reading firmware %s\n", fname);
rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
if (rc < 0) {
if (rc == -ENOENT)
tuner_err("Error: firmware %s not found.\n",
@ -917,22 +917,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
* that xc2028 will be in a safe state.
* Maybe this might also be needed for DTV.
*/
if (new_mode == T_ANALOG_TV) {
if (new_mode == T_ANALOG_TV)
rc = send_seq(priv, {0x00, 0x00});
} else if (priv->cur_fw.type & ATSC) {
offset = 1750000;
} else {
offset = 2750000;
/*
* Digital modes require an offset to adjust to the
* proper frequency.
* Analog modes require offset = 0
*/
if (new_mode == T_DIGITAL_TV) {
/* Sets the offset according with firmware */
if (priv->cur_fw.type & DTV6)
offset = 1750000;
else if (priv->cur_fw.type & DTV7)
offset = 2250000;
else /* DTV8 or DTV78 */
offset = 2750000;
/*
* We must adjust the offset by 500kHz in two cases in order
* to correctly center the IF output:
* 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
* selected and a 7MHz channel is tuned;
* 2) When tuning a VHF channel with DTV78 firmware.
* We must adjust the offset by 500kHz when
* tuning a 7MHz VHF channel with DTV78 firmware
* (used in Australia, Italy and Germany)
*/
if (((priv->cur_fw.type & DTV7) &&
(priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
((priv->cur_fw.type & DTV78) && freq < 470000000))
if ((priv->cur_fw.type & DTV78) && freq < 470000000)
offset -= 500000;
}
@ -991,7 +998,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
if (priv->ctrl.input1)
type |= INPUT1;
return generic_set_freq(fe, (625l * p->frequency) / 10,
T_ANALOG_TV, type, 0, 0);
T_RADIO, type, 0, 0);
}
/* if std is not defined, choose one */
@ -1022,21 +1029,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
switch(fe->ops.info.type) {
case FE_OFDM:
bw = p->u.ofdm.bandwidth;
break;
case FE_QAM:
tuner_info("WARN: There are some reports that "
"QAM 6 MHz doesn't work.\n"
"If this works for you, please report by "
"e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
bw = BANDWIDTH_6_MHZ;
type |= QAM;
/*
* The only countries with 6MHz seem to be Taiwan/Uruguay.
* Both seem to require QAM firmware for OFDM decoding
* Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
*/
if (bw == BANDWIDTH_6_MHZ)
type |= QAM;
break;
case FE_ATSC:
bw = BANDWIDTH_6_MHZ;
/* The only ATSC firmware (at least on v2.7) is D2633 */
type |= ATSC | D2633;
break;
/* DVB-S is not supported */
/* DVB-S and pure QAM (FE_QAM) are not supported */
default:
return -EINVAL;
}

View file

@ -3,6 +3,7 @@
*
* Copyright (c) 2007 Xceive Corporation
* Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
* Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -36,14 +37,20 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
static int no_poweroff;
module_param(no_poweroff, int, 0644);
MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
"\t\t1 keep device energized and with tuner ready all the times.\n"
"\t\tFaster, but consumes more power and keeps the device hotter");
static DEFINE_MUTEX(xc5000_list_mutex);
static LIST_HEAD(hybrid_tuner_instance_list);
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
struct xc5000_priv {
struct tuner_i2c_props i2c_props;
@ -83,11 +90,11 @@ struct xc5000_priv {
#define XREG_D_CODE 0x04
#define XREG_IF_OUT 0x05
#define XREG_SEEK_MODE 0x07
#define XREG_POWER_DOWN 0x0A
#define XREG_POWER_DOWN 0x0A /* Obsolete */
#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
#define XREG_SMOOTHEDCVBS 0x0E
#define XREG_XTALFREQ 0x0F
#define XREG_FINERFFREQ 0x10
#define XREG_FINERFREQ 0x10
#define XREG_DDIMODE 0x11
#define XREG_ADC_ENV 0x00
@ -100,6 +107,7 @@ struct xc5000_priv {
#define XREG_VERSION 0x07
#define XREG_PRODUCT_ID 0x08
#define XREG_BUSY 0x09
#define XREG_BUILD 0x0D
/*
Basic firmware description. This will remain with
@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"FM Radio-INPUT1", 0x0208, 0x9002}
};
static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
static void xc5000_TunerReset(struct dvb_frontend *fe);
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
static int xc5000_TunerReset(struct dvb_frontend *fe);
static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
{
return xc5000_writeregs(priv, buf, len)
? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
return XC_RESULT_I2C_WRITE_FAILURE;
}
return XC_RESULT_SUCCESS;
}
/* This routine is never used because the only time we read data from the
i2c bus is when we read registers, and we want that to be an atomic i2c
transaction in case we are on a multi-master bus */
static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
{
return xc5000_readregs(priv, buf, len)
? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
}
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len };
static int xc_reset(struct dvb_frontend *fe)
{
xc5000_TunerReset(fe);
return XC_RESULT_SUCCESS;
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
return -EREMOTEIO;
}
return 0;
}
static void xc_wait(int wait_ms)
@ -219,7 +236,7 @@ static void xc_wait(int wait_ms)
msleep(wait_ms);
}
static void xc5000_TunerReset(struct dvb_frontend *fe)
static int xc5000_TunerReset(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
priv->i2c_props.adap->algo_data,
DVB_FRONTEND_COMPONENT_TUNER,
XC5000_TUNER_RESET, 0);
if (ret)
if (ret) {
printk(KERN_ERR "xc5000: reset failed\n");
} else
return XC_RESULT_RESET_FAILURE;
}
} else {
printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
return XC_RESULT_RESET_FAILURE;
}
return XC_RESULT_SUCCESS;
}
static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
{
u8 buf[4];
int WatchDogTimer = 5;
int WatchDogTimer = 100;
int result;
buf[0] = (regAddr >> 8) & 0xFF;
@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
/* busy flag cleared */
break;
} else {
xc_wait(100); /* wait 5 ms */
xc_wait(5); /* wait 5 ms */
WatchDogTimer--;
}
}
@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
return result;
}
static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
{
u8 buf[2];
int result;
buf[0] = (regAddr >> 8) & 0xFF;
buf[1] = regAddr & 0xFF;
result = xc_send_i2c_data(priv, buf, 2);
if (result != XC_RESULT_SUCCESS)
return result;
result = xc_read_i2c_data(priv, buf, 2);
if (result != XC_RESULT_SUCCESS)
return result;
*i2cData = buf[0] * 256 + buf[1];
return result;
}
static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
{
struct xc5000_priv *priv = fe->tuner_priv;
@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
if (len == 0x0000) {
/* RESET command */
result = xc_reset(fe);
result = xc5000_TunerReset(fe);
index += 2;
if (result != XC_RESULT_SUCCESS)
return result;
@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
return ret;
}
static int xc_shutdown(struct xc5000_priv *priv)
{
return XC_RESULT_SUCCESS;
/* Fixme: cannot bring tuner back alive once shutdown
* without reloading the driver modules.
* return xc_write_reg(priv, XREG_POWER_DOWN, 0);
*/
}
static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
{
dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
@ -408,7 +402,10 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
freq_code = (u16)(freq_hz / 15625);
return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
/* Starting in firmware version 1.1.44, Xceive recommends using the
FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
only be used for fast scanning for channel lock) */
return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
}
@ -424,7 +421,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
{
return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
}
static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
@ -433,8 +430,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
u16 regData;
u32 tmp;
result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
if (result)
result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
if (result != XC_RESULT_SUCCESS)
return result;
tmp = (u32)regData;
@ -444,7 +441,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
{
return xc_read_reg(priv, XREG_LOCK, lock_status);
return xc5000_readreg(priv, XREG_LOCK, lock_status);
}
static int xc_get_version(struct xc5000_priv *priv,
@ -454,8 +451,8 @@ static int xc_get_version(struct xc5000_priv *priv,
u16 data;
int result;
result = xc_read_reg(priv, XREG_VERSION, &data);
if (result)
result = xc5000_readreg(priv, XREG_VERSION, &data);
if (result != XC_RESULT_SUCCESS)
return result;
(*hw_majorversion) = (data >> 12) & 0x0F;
@ -466,13 +463,18 @@ static int xc_get_version(struct xc5000_priv *priv,
return 0;
}
static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
{
return xc5000_readreg(priv, XREG_BUILD, buildrev);
}
static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
{
u16 regData;
int result;
result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
if (result)
result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
if (result != XC_RESULT_SUCCESS)
return result;
(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
@ -481,12 +483,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
{
return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
}
static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
{
return xc_read_reg(priv, XREG_QUALITY, quality);
return xc5000_readreg(priv, XREG_QUALITY, quality);
}
static u16 WaitForLock(struct xc5000_priv *priv)
@ -504,7 +506,9 @@ static u16 WaitForLock(struct xc5000_priv *priv)
return lockState;
}
static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
#define XC_TUNE_ANALOG 0
#define XC_TUNE_DIGITAL 1
static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
{
int found = 0;
@ -513,8 +517,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
return 0;
if (WaitForLock(priv) == 1)
found = 1;
if (mode == XC_TUNE_ANALOG) {
if (WaitForLock(priv) == 1)
found = 1;
}
return found;
}
@ -536,32 +542,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
}
*val = (bval[0] << 8) | bval[1];
return 0;
}
static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = 0, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
(int)len);
return -EREMOTEIO;
}
return 0;
}
static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
{
struct i2c_msg msg = { .addr = priv->i2c_props.addr,
.flags = I2C_M_RD, .buf = buf, .len = len };
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
return -EREMOTEIO;
}
return 0;
return XC_RESULT_SUCCESS;
}
static int xc5000_fwupload(struct dvb_frontend *fe)
@ -575,13 +556,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
XC5000_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
&priv->i2c_props.adap->dev);
priv->i2c_props.adap->dev.parent);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
ret = XC_RESULT_RESET_FAILURE;
goto out;
} else {
printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
fw->size);
ret = XC_RESULT_SUCCESS;
}
@ -590,8 +571,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
printk(KERN_ERR "xc5000: firmware incorrect size\n");
ret = XC_RESULT_RESET_FAILURE;
} else {
printk(KERN_INFO "xc5000: firmware upload\n");
printk(KERN_INFO "xc5000: firmware uploading...\n");
ret = xc_load_i2c_sequence(fe, fw->data);
printk(KERN_INFO "xc5000: firmware upload complete...\n");
}
out:
@ -609,6 +591,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
u16 quality;
u8 hw_majorversion = 0, hw_minorversion = 0;
u8 fw_majorversion = 0, fw_minorversion = 0;
u16 fw_buildversion = 0;
/* Wait for stats to stabilize.
* Frame Lines needs two frame times after initial lock
@ -628,9 +611,10 @@ static void xc_debug_dump(struct xc5000_priv *priv)
xc_get_version(priv, &hw_majorversion, &hw_minorversion,
&fw_majorversion, &fw_minorversion);
dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
xc_get_buildversion(priv, &fw_buildversion);
dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
hw_majorversion, hw_minorversion,
fw_majorversion, fw_minorversion);
fw_majorversion, fw_minorversion, fw_buildversion);
xc_get_hsync_freq(priv, &hsync_freq_hz);
dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
@ -648,27 +632,57 @@ static int xc5000_set_params(struct dvb_frontend *fe,
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
xc_load_fw_and_init_tuner(fe);
dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
dprintk(1, "%s() VSB modulation\n", __func__);
if (fe->ops.info.type == FE_ATSC) {
dprintk(1, "%s() ATSC\n", __func__);
switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
dprintk(1, "%s() VSB modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_AIR;
priv->freq_hz = params->frequency - 1750000;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
break;
case QAM_64:
case QAM_256:
case QAM_AUTO:
dprintk(1, "%s() QAM modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_CABLE;
priv->freq_hz = params->frequency - 1750000;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
break;
default:
return -EINVAL;
}
} else if (fe->ops.info.type == FE_OFDM) {
dprintk(1, "%s() OFDM\n", __func__);
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
priv->freq_hz = params->frequency - 1750000;
break;
case BANDWIDTH_7_MHZ:
printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
return -EINVAL;
case BANDWIDTH_8_MHZ:
priv->bandwidth = BANDWIDTH_8_MHZ;
priv->video_standard = DTV8;
priv->freq_hz = params->frequency - 2750000;
break;
default:
printk(KERN_ERR "xc5000 bandwidth not set!\n");
return -EINVAL;
}
priv->rf_mode = XC_RF_MODE_AIR;
priv->freq_hz = params->frequency - 1750000;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
break;
case QAM_64:
case QAM_256:
case QAM_AUTO:
dprintk(1, "%s() QAM modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_CABLE;
priv->freq_hz = params->frequency - 1750000;
priv->bandwidth = BANDWIDTH_6_MHZ;
priv->video_standard = DTV6;
break;
default:
} else {
printk(KERN_ERR "xc5000 modulation type not supported!\n");
return -EINVAL;
}
@ -698,7 +712,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
return -EIO;
}
xc_tune_channel(priv, priv->freq_hz);
xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
if (debug)
xc_debug_dump(priv);
@ -725,8 +739,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
return ret;
}
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
static int xc5000_set_analog_params(struct dvb_frontend *fe,
struct analog_parameters *params)
{
@ -807,7 +819,7 @@ tune_channel:
return -EREMOTEIO;
}
xc_tune_channel(priv, priv->freq_hz);
xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
if (debug)
xc_debug_dump(priv);
@ -875,18 +887,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
static int xc5000_sleep(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
dprintk(1, "%s()\n", __func__);
/* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
* once shutdown without reloading the driver. Maybe I am not
* doing something right.
*
*/
/* Avoid firmware reload on slow devices */
if (no_poweroff)
return 0;
ret = xc_shutdown(priv);
/* According to Xceive technical support, the "powerdown" register
was removed in newer versions of the firmware. The "supported"
way to sleep the tuner is to pull the reset pin low for 10ms */
ret = xc5000_TunerReset(fe);
if (ret != XC_RESULT_SUCCESS) {
printk(KERN_ERR
"xc5000: %s() unable to shutdown tuner\n",
@ -991,7 +1003,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
goto fail;
switch (id) {

View file

@ -1,9 +1,7 @@
/*
* This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
*
* flexcop-common.h - common header file for device-specific source files also.
*
* see flexcop.c for copyright information.
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-common.h - common header file for device-specific source files
* see flexcop.c for copyright information
*/
#ifndef __FLEXCOP_COMMON_H__
#define __FLEXCOP_COMMON_H__

File diff suppressed because it is too large Load diff

View file

@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
msgs[i].buf[0], &msgs[i].buf[1],
msgs[i].len - 1);
if (ret < 0) {
err("i2c master_xfer failed");
deb_i2c("i2c master_xfer failed");
break;
}
}

View file

@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = {
};
static const char *flexcop_device_names[] = {
"Unknown device",
"Air2PC/AirStar 2 DVB-T",
"Air2PC/AirStar 2 ATSC 1st generation",
"Air2PC/AirStar 2 ATSC 2nd generation",
"Sky2PC/SkyStar 2 DVB-S",
"Sky2PC/SkyStar 2 DVB-S (old version)",
"Cable2PC/CableStar 2 DVB-C",
"Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
"Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
"Sky2PC/SkyStar 2 DVB-S rev 2.8",
[FC_UNK] = "Unknown device",
[FC_CABLE] = "Cable2PC/CableStar 2 DVB-C",
[FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T",
[FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation",
[FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation",
[FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
[FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
[FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
[FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
[FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
};
static const char *flexcop_bus_names[] = {

View file

@ -508,12 +508,6 @@ static int __devinit bt878_probe(struct pci_dev *dev,
pci_set_master(dev);
pci_set_drvdata(dev, bt);
/* if(init_bt878(btv) < 0) {
bt878_remove(dev);
return -EIO;
}
*/
if ((result = bt878_mem_alloc(bt))) {
printk(KERN_ERR "bt878: failed to allocate memory!\n");
goto fail2;
@ -579,7 +573,7 @@ static struct pci_driver bt878_pci_driver = {
.name = "bt878",
.id_table = bt878_pci_tbl,
.probe = bt878_probe,
.remove = bt878_remove,
.remove = __devexit_p(bt878_remove),
};
static int bt878_pci_driver_registered;

View file

@ -51,6 +51,9 @@
#ifndef PCI_VENDOR_ID_TRIGEM
#define PCI_VENDOR_ID_TRIGEM 0x109f
#endif
#ifndef PCI_VENDOR_ID_AXESS
#define PCI_VENDOR_ID_AXESS 0x195d
#endif
#ifndef PCI_DEVICE_ID_DM1105
#define PCI_DEVICE_ID_DM1105 0x036f
#endif
@ -60,6 +63,9 @@
#ifndef PCI_DEVICE_ID_DW2004
#define PCI_DEVICE_ID_DW2004 0x2004
#endif
#ifndef PCI_DEVICE_ID_DM05
#define PCI_DEVICE_ID_DM05 0x1105
#endif
/* ----------------------------------------------- */
/* sdmc dm1105 registers */
@ -150,6 +156,11 @@
#define DM1105_LNB_13V 0x00010100
#define DM1105_LNB_18V 0x00000100
/* GPIO's for LNB power control for Axess DM05 */
#define DM05_LNB_MASK 0x00000000
#define DM05_LNB_13V 0x00020000
#define DM05_LNB_18V 0x00030000
static int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
@ -188,6 +199,8 @@ struct dm1105dvb {
/* irq */
struct work_struct work;
struct workqueue_struct *wq;
char wqn[16];
/* dma */
dma_addr_t dma_addr;
@ -313,15 +326,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
u32 lnb_mask, lnb_13v, lnb_18v;
if (voltage == SEC_VOLTAGE_18) {
outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
} else {
/*LNB ON-13V by default!*/
outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
}
switch (dm1105dvb->pdev->subsystem_device) {
case PCI_DEVICE_ID_DM05:
lnb_mask = DM05_LNB_MASK;
lnb_13v = DM05_LNB_13V;
lnb_18v = DM05_LNB_18V;
break;
default:
lnb_mask = DM1105_LNB_MASK;
lnb_13v = DM1105_LNB_13V;
lnb_18v = DM1105_LNB_18V;
}
outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
if (voltage == SEC_VOLTAGE_18)
outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
else
outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
return 0;
}
@ -440,7 +463,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
case (INTSTS_TSIRQ | INTSTS_IR):
dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
inl(dm_io_mem(DM1105_STADR));
schedule_work(&dm1105dvb->work);
queue_work(dm1105dvb->wq, &dm1105dvb->work);
break;
case INTSTS_IR:
dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
@ -567,46 +590,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
int ret;
switch (dm1105dvb->pdev->subsystem_device) {
case PCI_DEVICE_ID_DW2002:
dm1105dvb->fe = dvb_attach(
stv0299_attach, &sharp_z0194a_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe) {
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
}
if (!dm1105dvb->fe) {
dm1105dvb->fe = dvb_attach(
stv0288_attach, &earda_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe) {
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
&dm1105dvb->i2c_adap);
}
}
if (!dm1105dvb->fe) {
dm1105dvb->fe = dvb_attach(
si21xx_attach, &serit_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe)
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
}
break;
case PCI_DEVICE_ID_DW2004:
dm1105dvb->fe = dvb_attach(
cx24116_attach, &serit_sp2633_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe)
dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
break;
default:
dm1105dvb->fe = dvb_attach(
stv0299_attach, &sharp_z0194a_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe) {
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
&dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
break;
}
dm1105dvb->fe = dvb_attach(
stv0288_attach, &earda_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe) {
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
&dm1105dvb->i2c_adap);
break;
}
dm1105dvb->fe = dvb_attach(
si21xx_attach, &serit_config,
&dm1105dvb->i2c_adap);
if (dm1105dvb->fe)
dm1105dvb->fe->ops.set_voltage =
dm1105dvb_set_voltage;
}
if (!dm1105dvb->fe) {
@ -630,10 +651,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
static u8 command[1] = { 0x28 };
struct i2c_msg msg[] = {
{ .addr = IIC_24C01_addr >> 1, .flags = 0,
.buf = command, .len = 1 },
{ .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
.buf = mac, .len = 6 },
{
.addr = IIC_24C01_addr >> 1,
.flags = 0,
.buf = command,
.len = 1
}, {
.addr = IIC_24C01_addr >> 1,
.flags = I2C_M_RD,
.buf = mac,
.len = 6
},
};
dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
@ -752,14 +780,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
dm1105_ir_init(dm1105dvb);
INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
if (!dm1105dvb->wq)
goto err_dvb_net;
ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
DRIVER_NAME, dm1105dvb);
if (ret < 0)
goto err_free_irq;
goto err_workqueue;
return 0;
err_workqueue:
destroy_workqueue(dm1105dvb->wq);
err_dvb_net:
dvb_net_release(&dm1105dvb->dvbnet);
err_disconnect_frontend:
dmx->disconnect_frontend(dmx);
err_remove_mem_frontend:
@ -776,8 +812,6 @@ err_i2c_del_adapter:
i2c_del_adapter(&dm1105dvb->i2c_adap);
err_dm1105dvb_hw_exit:
dm1105dvb_hw_exit(dm1105dvb);
err_free_irq:
free_irq(pdev->irq, dm1105dvb);
err_pci_iounmap:
pci_iounmap(pdev, dm1105dvb->io_mem);
err_pci_release_regions:
@ -833,6 +867,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
.device = PCI_DEVICE_ID_DM1105,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_DEVICE_ID_DW2004,
}, {
.vendor = PCI_VENDOR_ID_AXESS,
.device = PCI_DEVICE_ID_DM05,
.subvendor = PCI_VENDOR_ID_AXESS,
.subdevice = PCI_DEVICE_ID_DM05,
}, {
/* empty */
},

View file

@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
if (dmxdev->exit) {
mutex_unlock(&dmxdev->mutex);
if (dmxdev->exit)
return -ENODEV;
}
//mutex_lock(&dmxdev->mutex);
ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
//mutex_unlock(&dmxdev->mutex);
return ret;
return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags & O_NONBLOCK,
buf, count, ppos);
}
static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,

View file

@ -38,6 +38,16 @@
*/
// #define DVB_DEMUX_SECTION_LOSS_LOG
static int dvb_demux_tscheck;
module_param(dvb_demux_tscheck, int, 0644);
MODULE_PARM_DESC(dvb_demux_tscheck,
"enable transport stream continuity and TEI check");
#define dprintk_tscheck(x...) do { \
if (dvb_demux_tscheck && printk_ratelimit()) \
printk(x); \
} while (0)
/******************************************************************************
* static inlined helper functions
******************************************************************************/
@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
u16 pid = ts_pid(buf);
int dvr_done = 0;
if (dvb_demux_tscheck) {
if (!demux->cnt_storage)
demux->cnt_storage = vmalloc(MAX_PID + 1);
if (!demux->cnt_storage) {
printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
dvb_demux_tscheck = 0;
goto no_dvb_demux_tscheck;
}
/* check pkt counter */
if (pid < MAX_PID) {
if (buf[1] & 0x80)
dprintk_tscheck("TEI detected. "
"PID=0x%x data1=0x%x\n",
pid, buf[1]);
if ((buf[3] & 0xf) != demux->cnt_storage[pid])
dprintk_tscheck("TS packet counter mismatch. "
"PID=0x%x expected 0x%x "
"got 0x%x\n",
pid, demux->cnt_storage[pid],
buf[3] & 0xf);
demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
};
/* end check */
};
no_dvb_demux_tscheck:
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
int i;
struct dmx_demux *dmx = &dvbdemux->dmx;
dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0;
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
void dvb_dmx_release(struct dvb_demux *dvbdemux)
{
vfree(dvbdemux->cnt_storage);
vfree(dvbdemux->filter);
vfree(dvbdemux->feed);
}

View file

@ -42,6 +42,8 @@
#define DVB_DEMUX_MASK_MAX 18
#define MAX_PID 0x1fff
struct dvb_demux_filter {
struct dmx_section_filter filter;
u8 maskandmode[DMX_MAX_FILTER_SIZE];
@ -127,6 +129,8 @@ struct dvb_demux {
struct mutex mutex;
spinlock_t lock;
uint8_t *cnt_storage; /* for TS continuity check */
};
int dvb_dmx_init(struct dvb_demux *dvbdemux);

View file

@ -543,6 +543,7 @@ restart:
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
fepriv->exit = 1;
break;
}
@ -656,6 +657,7 @@ restart:
}
fepriv->thread = NULL;
fepriv->exit = 0;
mb();
dvb_frontend_wakeup(fe);

View file

@ -261,6 +261,7 @@ config DVB_USB_DW2102
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
help
Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
and the TeVii S650.

View file

@ -40,7 +40,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static DEFINE_MUTEX(af9015_usb_mutex);
static struct af9015_config af9015_config;
static struct dvb_usb_device_properties af9015_properties[2];
static struct dvb_usb_device_properties af9015_properties[3];
static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
static struct af9013_config af9015_af9013_config[] = {
@ -538,7 +538,7 @@ exit:
/* dump eeprom */
static int af9015_eeprom_dump(struct dvb_usb_device *d)
{
char buf[52], buf2[4];
char buf[4+3*16+1], buf2[4];
u8 reg, val;
for (reg = 0; ; reg++) {
@ -1261,7 +1261,11 @@ static struct usb_device_id af9015_usb_table[] = {
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
{USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
{USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@ -1321,7 +1325,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 9,
.num_device_descs = 9, /* max 9 */
.devices = {
{
.name = "Afatech AF9015 DVB-T USB2.0 stick",
@ -1426,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 9,
.num_device_descs = 9, /* max 9 */
.devices = {
{
.name = "Xtensions XD-380",
@ -1478,7 +1482,85 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.warm_ids = {NULL},
},
}
}
}, {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.download_firmware = af9015_download_firmware,
.firmware = "dvb-usb-af9015.fw",
.no_reconnect = 1,
.size_of_priv = sizeof(struct af9015_state), \
.num_adapters = 2,
.adapter = {
{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.pid_filter_count = 32,
.pid_filter = af9015_pid_filter,
.pid_filter_ctrl = af9015_pid_filter_ctrl,
.frontend_attach =
af9015_af9013_frontend_attach,
.tuner_attach = af9015_tuner_attach,
.stream = {
.type = USB_BULK,
.count = 6,
.endpoint = 0x84,
},
},
{
.frontend_attach =
af9015_af9013_frontend_attach,
.tuner_attach = af9015_tuner_attach,
.stream = {
.type = USB_BULK,
.count = 6,
.endpoint = 0x85,
.u = {
.bulk = {
.buffersize =
TS_USB20_MAX_PACKET_SIZE,
}
}
},
}
},
.identify_state = af9015_identify_state,
.rc_query = af9015_rc_query,
.rc_interval = 150,
.i2c_algo = &af9015_i2c_algo,
.num_device_descs = 4, /* max 9 */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
.cold_ids = {&af9015_usb_table[21], NULL},
.warm_ids = {NULL},
},
{
.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
"V3.0",
.cold_ids = {&af9015_usb_table[22], NULL},
.warm_ids = {NULL},
},
{
.name = "KWorld Digial MC-810",
.cold_ids = {&af9015_usb_table[23], NULL},
.warm_ids = {NULL},
},
{
.name = "Genius TVGo DVB-T03",
.cold_ids = {&af9015_usb_table[24], NULL},
.warm_ids = {NULL},
},
}
},
};
static int af9015_usb_probe(struct usb_interface *intf,

View file

@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component,
if (command == XC5000_TUNER_RESET) {
/* Reset the tuner */
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
msleep(330); /* from Windows USB trace */
msleep(10);
dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
msleep(330); /* from Windows USB trace */
msleep(10);
} else {
err("xc5000: unknown tuner callback command: %d\n", command);
return -EINVAL;
@ -1493,6 +1493,10 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) },
{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) },
/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) },
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@ -1692,7 +1696,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
.num_device_descs = 11,
.num_device_descs = 12,
.devices = {
{ "DiBcom STK7070P reference design",
{ &dib0700_usb_id_table[15], NULL },
@ -1726,8 +1730,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[30], NULL },
{ NULL },
},
{ "Terratec Cinergy T USB XXS",
{ &dib0700_usb_id_table[33], NULL },
{ "Terratec Cinergy T USB XXS/ T3",
{ &dib0700_usb_id_table[33],
&dib0700_usb_id_table[52], NULL },
{ NULL },
},
{ "Elgato EyeTV DTT",
@ -1738,6 +1743,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[45], NULL },
{ NULL },
},
{ "Elgato EyeTV Dtt Dlx PD378S",
{ &dib0700_usb_id_table[50], NULL },
{ NULL },
},
},
.rc_interval = DEFAULT_RC_INTERVAL,
@ -1784,8 +1793,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[36], NULL },
{ NULL },
},
{ "Terratec Cinergy DT USB XS Diversity",
{ &dib0700_usb_id_table[43], NULL },
{ "Terratec Cinergy DT USB XS Diversity/ T5",
{ &dib0700_usb_id_table[43],
&dib0700_usb_id_table[53], NULL},
{ NULL },
},
{ "Sony PlayTV",
@ -1812,7 +1822,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
.num_device_descs = 7,
.num_device_descs = 8,
.devices = {
{ "Terratec Cinergy HT USB XE",
{ &dib0700_usb_id_table[27], NULL },
@ -1842,6 +1852,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[48], NULL },
{ NULL },
},
{ "Leadtek WinFast DTV Dongle H",
{ &dib0700_usb_id_table[51], NULL },
{ NULL },
},
},
.rc_interval = DEFAULT_RC_INTERVAL,
.rc_key_map = dib0700_rc_keys,

View file

@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
for (i = 0; i < num; i++) {
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
&& (msg[i+1].flags & I2C_M_RD)) {
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
msg[i+1].buf,msg[i+1].len) < 0)
break;
i++;
} else
} else if ((msg[i].flags & I2C_M_RD) == 0) {
if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
break;
} else
break;
}
mutex_unlock(&d->i2c_mutex);

View file

@ -80,6 +80,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_CONCEPTRONIC_CTVDIGRCU 0xe397
#define USB_PID_CONEXANT_D680_DMB 0x86d6
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
@ -97,6 +98,7 @@
#define USB_PID_DPOSH_M9206_COLD 0x9206
#define USB_PID_DPOSH_M9206_WARM 0xa090
#define USB_PID_UNIWILL_STK7700P 0x6003
#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_INTEL_CE9500 0x9500
@ -104,6 +106,7 @@
#define USB_PID_KWORLD_395U 0xe396
#define USB_PID_KWORLD_395U_2 0xe39b
#define USB_PID_KWORLD_395U_3 0xe395
#define USB_PID_KWORLD_MC810 0xc810
#define USB_PID_KWORLD_PC160_2T 0xc160
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
@ -171,6 +174,7 @@
#define USB_PID_AVERMEDIA_A309 0xa309
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
#define USB_PID_AVERMEDIA_A805 0xa805
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
@ -178,6 +182,8 @@
#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060
#define USB_PID_TERRATEC_CINERGY_T_EXPRESS 0x0062
#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
#define USB_PID_TERRATEC_T3 0x10a0
#define USB_PID_TERRATEC_T5 0x10a1
#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
#define USB_PID_PINNACLE_PCTV2000E 0x022c
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
@ -222,6 +228,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
@ -251,5 +258,6 @@
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
#define USB_PID_SONY_PLAYTV 0x0003
#define USB_PID_ELGATO_EYETV_DTT 0x0021
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
#endif

View file

@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
int generic_bulk_ctrl_endpoint;
int num_device_descs;
struct dvb_usb_device_description devices[11];
struct dvb_usb_device_description devices[12];
};
/**

View file

@ -1,7 +1,7 @@
/* DVB USB framework compliant Linux driver for the
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
*
* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
* TeVii S600, S650 Cards
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
*
* 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
@ -17,6 +17,7 @@
#include "stb6000.h"
#include "eds1547.h"
#include "cx24116.h"
#include "tda1002x.h"
#ifndef USB_PID_DW2102
#define USB_PID_DW2102 0x2102
@ -26,10 +27,18 @@
#define USB_PID_DW2104 0x2104
#endif
#ifndef USB_PID_DW3101
#define USB_PID_DW3101 0x3101
#endif
#ifndef USB_PID_CINERGY_S
#define USB_PID_CINERGY_S 0x0064
#endif
#ifndef USB_PID_TEVII_S650
#define USB_PID_TEVII_S650 0xd650
#endif
#define DW210X_READ_MSG 0
#define DW210X_WRITE_MSG 1
@ -40,18 +49,21 @@
#define DW2102_VOLTAGE_CTRL (0x1800)
#define DW2102_RC_QUERY (0x1a00)
struct dw210x_state {
u32 last_key_pressed;
};
struct dw210x_rc_keys {
u32 keycode;
u32 event;
struct dvb_usb_rc_keys_table {
struct dvb_usb_rc_key *rc_keys;
int rc_keys_size;
};
/* debug */
static int dvb_usb_dw2102_debug;
module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
DVB_USB_DEBUG_STATUS);
/* keymaps */
static int ir_keymap;
module_param_named(keymap, ir_keymap, int, 0644);
MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ...");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int i = 0, ret = 0;
u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
u16 value;
@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
mutex_unlock(&d->i2c_mutex);
return num;
}
static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
case 2: {
/* read */
/* first write first register number */
u8 ibuf [msg[1].len + 2], obuf[3];
u8 ibuf[msg[1].len + 2], obuf[3];
obuf[0] = 0xd0;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
case 2: {
/* read */
/* first write first register number */
u8 ibuf [msg[1].len + 2], obuf[3];
u8 ibuf[msg[1].len + 2], obuf[3];
obuf[0] = 0xaa;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
return num;
}
static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret = 0, i;
if (!d)
return -ENODEV;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
switch (num) {
case 2: {
/* read */
/* first write first register number */
u8 ibuf[msg[1].len + 2], obuf[3];
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
/* second read registers */
ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
ibuf, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
break;
}
case 1:
switch (msg[0].addr) {
case 0x60:
case 0x0c: {
/* write to register */
u8 obuf[msg[0].len + 2];
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case(DW2102_RC_QUERY): {
u8 ibuf[2];
ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
ibuf, 2, DW210X_READ_MSG);
memcpy(msg[0].buf, ibuf , 2);
break;
}
}
break;
}
for (i = 0; i < num; i++) {
deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
msg[i].flags == 0 ? ">>>" : "<<<");
debug_dump(msg[i].buf, msg[i].len, deb_xfer);
}
mutex_unlock(&d->i2c_mutex);
return num;
}
static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
@ -385,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = {
.functionality = dw210x_i2c_func,
};
static struct i2c_algorithm dw3101_i2c_algo = {
.master_xfer = dw3101_i2c_transfer,
.functionality = dw210x_i2c_func,
};
static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
{
int i;
@ -404,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
debug_dump(eepromline, 16, deb_xfer);
}
}
memcpy(mac, eeprom + 8, 6);
return 0;
};
@ -448,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = {
};
static struct tda10023_config dw3101_tda10023_config = {
.demod_address = 0x0c,
.invert = 1,
};
static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
{
if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@ -460,6 +547,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
}
static struct dvb_usb_device_properties dw2102_properties;
static struct dvb_usb_device_properties dw2104_properties;
static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
{
@ -497,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
return -EIO;
}
static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
{
d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
&d->dev->i2c_adap, 0x48);
if (d->fe != NULL) {
info("Attached tda10023!\n");
return 0;
}
return -EIO;
}
static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@ -512,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
&adap->dev->i2c_adap, DVB_PLL_TUA6034);
return 0;
}
static struct dvb_usb_rc_key dw210x_rc_keys[] = {
{ 0xf8, 0x0a, KEY_Q }, /*power*/
{ 0xf8, 0x0c, KEY_M }, /*mute*/
@ -544,44 +651,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = {
{ 0xf8, 0x40, KEY_F }, /*full*/
{ 0xf8, 0x1e, KEY_W }, /*tvmode*/
{ 0xf8, 0x1b, KEY_B }, /*recall*/
};
static struct dvb_usb_rc_key tevii_rc_keys[] = {
{ 0xf8, 0x0a, KEY_POWER },
{ 0xf8, 0x0c, KEY_MUTE },
{ 0xf8, 0x11, KEY_1 },
{ 0xf8, 0x12, KEY_2 },
{ 0xf8, 0x13, KEY_3 },
{ 0xf8, 0x14, KEY_4 },
{ 0xf8, 0x15, KEY_5 },
{ 0xf8, 0x16, KEY_6 },
{ 0xf8, 0x17, KEY_7 },
{ 0xf8, 0x18, KEY_8 },
{ 0xf8, 0x19, KEY_9 },
{ 0xf8, 0x10, KEY_0 },
{ 0xf8, 0x1c, KEY_MENU },
{ 0xf8, 0x0f, KEY_VOLUMEDOWN },
{ 0xf8, 0x1a, KEY_LAST },
{ 0xf8, 0x0e, KEY_OPEN },
{ 0xf8, 0x04, KEY_RECORD },
{ 0xf8, 0x09, KEY_VOLUMEUP },
{ 0xf8, 0x08, KEY_CHANNELUP },
{ 0xf8, 0x07, KEY_PVR },
{ 0xf8, 0x0b, KEY_TIME },
{ 0xf8, 0x02, KEY_RIGHT },
{ 0xf8, 0x03, KEY_LEFT },
{ 0xf8, 0x00, KEY_UP },
{ 0xf8, 0x1f, KEY_OK },
{ 0xf8, 0x01, KEY_DOWN },
{ 0xf8, 0x05, KEY_TUNER },
{ 0xf8, 0x06, KEY_CHANNELDOWN },
{ 0xf8, 0x40, KEY_PLAYPAUSE },
{ 0xf8, 0x1e, KEY_REWIND },
{ 0xf8, 0x1b, KEY_FAVORITES },
{ 0xf8, 0x1d, KEY_BACK },
{ 0xf8, 0x4d, KEY_FASTFORWARD },
{ 0xf8, 0x44, KEY_EPG },
{ 0xf8, 0x4c, KEY_INFO },
{ 0xf8, 0x41, KEY_AB },
{ 0xf8, 0x43, KEY_AUDIO },
{ 0xf8, 0x45, KEY_SUBTITLE },
{ 0xf8, 0x4a, KEY_LIST },
{ 0xf8, 0x46, KEY_F1 },
{ 0xf8, 0x47, KEY_F2 },
{ 0xf8, 0x5e, KEY_F3 },
{ 0xf8, 0x5c, KEY_F4 },
{ 0xf8, 0x52, KEY_F5 },
{ 0xf8, 0x5a, KEY_F6 },
{ 0xf8, 0x56, KEY_MODE },
{ 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
};
static struct dvb_usb_rc_key tbs_rc_keys[] = {
{ 0xf8, 0x84, KEY_POWER },
{ 0xf8, 0x94, KEY_MUTE },
{ 0xf8, 0x87, KEY_1 },
{ 0xf8, 0x86, KEY_2 },
{ 0xf8, 0x85, KEY_3 },
{ 0xf8, 0x8b, KEY_4 },
{ 0xf8, 0x8a, KEY_5 },
{ 0xf8, 0x89, KEY_6 },
{ 0xf8, 0x8f, KEY_7 },
{ 0xf8, 0x8e, KEY_8 },
{ 0xf8, 0x8d, KEY_9 },
{ 0xf8, 0x92, KEY_0 },
{ 0xf8, 0x96, KEY_CHANNELUP },
{ 0xf8, 0x91, KEY_CHANNELDOWN },
{ 0xf8, 0x93, KEY_VOLUMEUP },
{ 0xf8, 0x8c, KEY_VOLUMEDOWN },
{ 0xf8, 0x83, KEY_RECORD },
{ 0xf8, 0x98, KEY_PAUSE },
{ 0xf8, 0x99, KEY_OK },
{ 0xf8, 0x9a, KEY_SHUFFLE },
{ 0xf8, 0x81, KEY_UP },
{ 0xf8, 0x90, KEY_LEFT },
{ 0xf8, 0x82, KEY_RIGHT },
{ 0xf8, 0x88, KEY_DOWN },
{ 0xf8, 0x95, KEY_FAVORITES },
{ 0xf8, 0x97, KEY_SUBTITLE },
{ 0xf8, 0x9d, KEY_ZOOM },
{ 0xf8, 0x9f, KEY_EXIT },
{ 0xf8, 0x9e, KEY_MENU },
{ 0xf8, 0x9c, KEY_EPG },
{ 0xf8, 0x80, KEY_PREVIOUS },
{ 0xf8, 0x9b, KEY_MODE }
};
static struct dvb_usb_rc_keys_table keys_tables[] = {
{ dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
{ tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
{ tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
};
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct dw210x_state *st = d->priv;
struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
int keymap_size = d->props.rc_key_map_size;
u8 key[2];
struct i2c_msg msg[] = {
{.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
.len = 2},
struct i2c_msg msg = {
.addr = DW2102_RC_QUERY,
.flags = I2C_M_RD,
.buf = key,
.len = 2
};
int i;
/* override keymap */
if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
keymap = keys_tables[ir_keymap - 1].rc_keys ;
keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
}
*state = REMOTE_NO_KEY_PRESSED;
if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
for (i = 0; i < keymap_size ; i++) {
if (keymap[i].data == msg.buf[0]) {
*state = REMOTE_KEY_PRESSED;
*event = dw210x_rc_keys[i].event;
st->last_key_pressed =
dw210x_rc_keys[i].event;
*event = keymap[i].event;
break;
}
st->last_key_pressed = 0;
}
if ((*state) == REMOTE_KEY_PRESSED)
deb_rc("%s: found rc key: %x, %x, event: %x\n",
__func__, key[0], key[1], (*event));
else if (key[0] != 0xff)
deb_rc("%s: unknown rc key: %x, %x\n",
__func__, key[0], key[1]);
}
/* info("key: %x %x\n",key[0],key[1]); */
return 0;
}
static struct usb_device_id dw2102_table[] = {
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
{USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
{USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
{USB_DEVICE(0x9022, 0xd650)},
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
{USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
{USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
{ }
};
@ -642,11 +852,16 @@ static int dw2102_load_firmware(struct usb_device *dev,
}
/* init registers */
switch (dev->descriptor.idProduct) {
case USB_PID_TEVII_S650:
dw2104_properties.rc_key_map = tevii_rc_keys;
dw2104_properties.rc_key_map_size =
ARRAY_SIZE(tevii_rc_keys);
case USB_PID_DW2104:
case 0xd650:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
DW210X_WRITE_MSG);
/* break omitted intentionally */
case USB_PID_DW3101:
reset = 0;
dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
DW210X_WRITE_MSG);
@ -690,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
DW210X_READ_MSG);
break;
}
msleep(100);
kfree(p);
}
@ -700,7 +916,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-dw2102.fw",
.size_of_priv = sizeof(struct dw210x_state),
.no_reconnect = 1,
.i2c_algo = &dw2102_serit_i2c_algo,
@ -714,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
.num_adapters = 1,
.download_firmware = dw2102_load_firmware,
.read_mac_address = dw210x_read_mac_address,
.adapter = {
.adapter = {
{
.frontend_attach = dw2102_frontend_attach,
.streaming_ctrl = NULL,
@ -752,7 +967,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-dw2104.fw",
.size_of_priv = sizeof(struct dw210x_state),
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
@ -796,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = {
}
};
static struct dvb_usb_device_properties dw3101_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
.firmware = "dvb-usb-dw3101.fw",
.no_reconnect = 1,
.i2c_algo = &dw3101_i2c_algo,
.rc_key_map = dw210x_rc_keys,
.rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
.rc_interval = 150,
.rc_query = dw2102_rc_query,
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
.num_adapters = 1,
.download_firmware = dw2102_load_firmware,
.read_mac_address = dw210x_read_mac_address,
.adapter = {
{
.frontend_attach = dw3101_frontend_attach,
.streaming_ctrl = NULL,
.tuner_attach = dw3101_tuner_attach,
.stream = {
.type = USB_BULK,
.count = 8,
.endpoint = 0x82,
.u = {
.bulk = {
.buffersize = 4096,
}
}
},
}
},
.num_device_descs = 1,
.devices = {
{ "DVBWorld DVB-C 3101 USB2.0",
{&dw2102_table[5], NULL},
{NULL},
},
}
};
static int dw2102_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw2104_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &dw3101_properties,
THIS_MODULE, NULL, adapter_nr)) {
return 0;
}
@ -833,6 +1092,8 @@ module_init(dw2102_module_init);
module_exit(dw2102_module_exit);
MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
" DVB-C 3101 USB2.0,"
" TeVii S600, S650 USB2.0 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");

View file

@ -5,4 +5,5 @@
#include "dvb-usb.h"
#define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
#define deb_rc(args...) dprintk(dvb_usb_dw2102_debug, 0x04, args)
#endif

View file

@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
{ 0 },
};
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 4,
.num_device_descs = 3,
.devices = {
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
@ -268,10 +268,6 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[3], NULL },
},
{ .name = "Genpix SkyWalker-CW3K DVB-S receiver",
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[4], NULL },
},
{ NULL },
}
};

View file

@ -18,7 +18,7 @@
#include "firedtv.h"
/* fixed table with older keycodes, geared towards MythTV */
const static u16 oldtable[] = {
static const u16 oldtable[] = {
/* code from device: 0x4501...0x451f */
@ -62,7 +62,7 @@ const static u16 oldtable[] = {
};
/* user-modifiable table for a remote as sold in 2008 */
const static u16 keytable[] = {
static const u16 keytable[] = {
/* code from device: 0x0300...0x031f */

View file

@ -35,6 +35,21 @@ config DVB_STB6100
A Silicon tuner from ST used in conjunction with the STB0899
demodulator. Say Y when you want to support this tuner.
config DVB_STV090x
tristate "STV0900/STV0903(A/B) based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
Say Y when you want to support these frontends.
config DVB_STV6110x
tristate "STV6110/(A) based tuners"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A Silicon tuner that supports DVB-S and DVB-S2 modes
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
@ -506,6 +521,13 @@ config DVB_ISL6421
help
An SEC control chip.
config DVB_ISL6423
tristate "ISL6423 SEC controller"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A SEC controller chip from Intersil
config DVB_LGS8GL5
tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
depends on DVB_CORE && I2C

View file

@ -71,4 +71,6 @@ obj-$(CONFIG_DVB_STB6000) += stb6000.o
obj-$(CONFIG_DVB_S921) += s921.o
obj-$(CONFIG_DVB_STV6110) += stv6110.o
obj-$(CONFIG_DVB_STV0900) += stv0900.o
obj-$(CONFIG_DVB_STV090x) += stv090x.o
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o

View file

@ -1455,7 +1455,7 @@ static int af9013_download_firmware(struct af9013_state *state)
af9013_ops.info.name);
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, &state->i2c->dev);
ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
if (ret) {
err("did not find the firmware file. (%s) "
"Please see linux/Documentation/dvb/ for more details" \

View file

@ -367,11 +367,90 @@ static struct {
{ 0x8231, 0x13 },
};
/* QAM Modulation table */
/* QAM64 Modulation table */
static struct {
u16 reg;
u16 data;
} QAM_mod_tab[] = {
} QAM64_mod_tab[] = {
{ 0x00a3, 0x09 },
{ 0x00a4, 0x00 },
{ 0x0081, 0xc4 },
{ 0x00a5, 0x40 },
{ 0x00aa, 0x77 },
{ 0x00ad, 0x77 },
{ 0x00a6, 0x67 },
{ 0x0262, 0x20 },
{ 0x021c, 0x30 },
{ 0x00b8, 0x3e },
{ 0x00b9, 0xf0 },
{ 0x00ba, 0x01 },
{ 0x00bb, 0x18 },
{ 0x00bc, 0x50 },
{ 0x00bd, 0x00 },
{ 0x00be, 0xea },
{ 0x00bf, 0xef },
{ 0x00c0, 0xfc },
{ 0x00c1, 0xbd },
{ 0x00c2, 0x1f },
{ 0x00c3, 0xfc },
{ 0x00c4, 0xdd },
{ 0x00c5, 0xaf },
{ 0x00c6, 0x00 },
{ 0x00c7, 0x38 },
{ 0x00c8, 0x30 },
{ 0x00c9, 0x05 },
{ 0x00ca, 0x4a },
{ 0x00cb, 0xd0 },
{ 0x00cc, 0x01 },
{ 0x00cd, 0xd9 },
{ 0x00ce, 0x6f },
{ 0x00cf, 0xf9 },
{ 0x00d0, 0x70 },
{ 0x00d1, 0xdf },
{ 0x00d2, 0xf7 },
{ 0x00d3, 0xc2 },
{ 0x00d4, 0xdf },
{ 0x00d5, 0x02 },
{ 0x00d6, 0x9a },
{ 0x00d7, 0xd0 },
{ 0x0250, 0x0d },
{ 0x0251, 0xcd },
{ 0x0252, 0xe0 },
{ 0x0253, 0x05 },
{ 0x0254, 0xa7 },
{ 0x0255, 0xff },
{ 0x0256, 0xed },
{ 0x0257, 0x5b },
{ 0x0258, 0xae },
{ 0x0259, 0xe6 },
{ 0x025a, 0x3d },
{ 0x025b, 0x0f },
{ 0x025c, 0x0d },
{ 0x025d, 0xea },
{ 0x025e, 0xf2 },
{ 0x025f, 0x51 },
{ 0x0260, 0xf5 },
{ 0x0261, 0x06 },
{ 0x021a, 0x00 },
{ 0x0546, 0x40 },
{ 0x0210, 0xc7 },
{ 0x0211, 0xaa },
{ 0x0212, 0xab },
{ 0x0213, 0x02 },
{ 0x0502, 0x00 },
{ 0x0121, 0x04 },
{ 0x0122, 0x04 },
{ 0x052e, 0x10 },
{ 0x00a4, 0xca },
{ 0x00a7, 0x40 },
{ 0x0526, 0x01 },
};
/* QAM256 Modulation table */
static struct {
u16 reg;
u16 data;
} QAM256_mod_tab[] = {
{ 0x80a3, 0x09 },
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
case QAM_256:
dprintk("%s() QAM 64/256\n", __func__);
for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
dprintk("%s() QAM 64\n", __func__);
for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
au8522_writereg(state,
QAM_mod_tab[i].reg,
QAM_mod_tab[i].data);
QAM64_mod_tab[i].reg,
QAM64_mod_tab[i].data);
au8522_set_if(fe, state->config->qam_if);
break;
case QAM_256:
dprintk("%s() QAM 256\n", __func__);
for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
au8522_writereg(state,
QAM256_mod_tab[i].reg,
QAM256_mod_tab[i].data);
au8522_set_if(fe, state->config->qam_if);
break;
default:

View file

@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
__func__, CX24116_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
&state->i2c->dev);
state->i2c->dev.parent);
printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
__func__);
if (ret) {

View file

@ -123,10 +123,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
}
memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
if (rc != 0) {
printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
mod_name, fw[ix].name);
rc = -ENOENT;
goto exit_err;
}

View file

@ -0,0 +1,308 @@
/*
Intersil ISL6423 SEC and LNB Power supply controller
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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 <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
#include "isl6423.h"
static unsigned int verbose;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
#define FE_ERROR 0
#define FE_NOTICE 1
#define FE_INFO 2
#define FE_DEBUG 3
#define FE_DEBUGREG 4
#define dprintk(__y, __z, format, arg...) do { \
if (__z) { \
if ((verbose > FE_ERROR) && (verbose > __y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_NOTICE) && (verbose > __y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_INFO) && (verbose > __y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_DEBUG) && (verbose > __y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (verbose > __y) \
printk(format, ##arg); \
} \
} while (0)
struct isl6423_dev {
const struct isl6423_config *config;
struct i2c_adapter *i2c;
u8 reg_3;
u8 reg_4;
unsigned int verbose;
};
static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
{
struct i2c_adapter *i2c = isl6423->i2c;
u8 addr = isl6423->config->addr;
int err = 0;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
dprintk(FE_DEBUG, 1, "write reg %02X", reg);
err = i2c_transfer(i2c, &msg, 1);
if (err < 0)
goto exit;
return 0;
exit:
dprintk(FE_ERROR, 1, "I/O error <%d>", err);
return err;
}
static int isl6423_set_modulation(struct dvb_frontend *fe)
{
struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
const struct isl6423_config *config = isl6423->config;
int err = 0;
u8 reg_2 = 0;
reg_2 = 0x01 << 5;
if (config->mod_extern)
reg_2 |= (1 << 3);
else
reg_2 |= (1 << 4);
err = isl6423_write(isl6423, reg_2);
if (err < 0)
goto exit;
return 0;
exit:
dprintk(FE_ERROR, 1, "I/O error <%d>", err);
return err;
}
static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
{
struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
u8 reg_3 = isl6423->reg_3;
u8 reg_4 = isl6423->reg_4;
int err = 0;
if (arg) {
/* EN = 1, VSPEN = 1, VBOT = 1 */
reg_4 |= (1 << 4);
reg_4 |= 0x1;
reg_3 |= (1 << 3);
} else {
/* EN = 1, VSPEN = 1, VBOT = 0 */
reg_4 |= (1 << 4);
reg_4 &= ~0x1;
reg_3 |= (1 << 3);
}
err = isl6423_write(isl6423, reg_3);
if (err < 0)
goto exit;
err = isl6423_write(isl6423, reg_4);
if (err < 0)
goto exit;
isl6423->reg_3 = reg_3;
isl6423->reg_4 = reg_4;
return 0;
exit:
dprintk(FE_ERROR, 1, "I/O error <%d>", err);
return err;
}
static int isl6423_set_voltage(struct dvb_frontend *fe,
enum fe_sec_voltage voltage)
{
struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
u8 reg_3 = isl6423->reg_3;
u8 reg_4 = isl6423->reg_4;
int err = 0;
switch (voltage) {
case SEC_VOLTAGE_OFF:
/* EN = 0 */
reg_4 &= ~(1 << 4);
break;
case SEC_VOLTAGE_13:
/* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
reg_4 |= (1 << 4);
reg_4 &= ~0x3;
reg_3 |= (1 << 3);
break;
case SEC_VOLTAGE_18:
/* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
reg_4 |= (1 << 4);
reg_4 |= 0x2;
reg_4 &= ~0x1;
reg_3 |= (1 << 3);
break;
default:
break;
}
err = isl6423_write(isl6423, reg_3);
if (err < 0)
goto exit;
err = isl6423_write(isl6423, reg_4);
if (err < 0)
goto exit;
isl6423->reg_3 = reg_3;
isl6423->reg_4 = reg_4;
return 0;
exit:
dprintk(FE_ERROR, 1, "I/O error <%d>", err);
return err;
}
static int isl6423_set_current(struct dvb_frontend *fe)
{
struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
u8 reg_3 = isl6423->reg_3;
const struct isl6423_config *config = isl6423->config;
int err = 0;
switch (config->current_max) {
case SEC_CURRENT_275m:
/* 275mA */
/* ISELH = 0, ISELL = 0 */
reg_3 &= ~0x3;
break;
case SEC_CURRENT_515m:
/* 515mA */
/* ISELH = 0, ISELL = 1 */
reg_3 &= ~0x2;
reg_3 |= 0x1;
break;
case SEC_CURRENT_635m:
/* 635mA */
/* ISELH = 1, ISELL = 0 */
reg_3 &= ~0x1;
reg_3 |= 0x2;
break;
case SEC_CURRENT_800m:
/* 800mA */
/* ISELH = 1, ISELL = 1 */
reg_3 |= 0x3;
break;
}
err = isl6423_write(isl6423, reg_3);
if (err < 0)
goto exit;
switch (config->curlim) {
case SEC_CURRENT_LIM_ON:
/* DCL = 0 */
reg_3 &= ~0x10;
break;
case SEC_CURRENT_LIM_OFF:
/* DCL = 1 */
reg_3 |= 0x10;
break;
}
err = isl6423_write(isl6423, reg_3);
if (err < 0)
goto exit;
isl6423->reg_3 = reg_3;
return 0;
exit:
dprintk(FE_ERROR, 1, "I/O error <%d>", err);
return err;
}
static void isl6423_release(struct dvb_frontend *fe)
{
isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
kfree(fe->sec_priv);
fe->sec_priv = NULL;
}
struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct isl6423_config *config)
{
struct isl6423_dev *isl6423;
isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
if (!isl6423)
return NULL;
isl6423->config = config;
isl6423->i2c = i2c;
fe->sec_priv = isl6423;
/* SR3H = 0, SR3M = 1, SR3L = 0 */
isl6423->reg_3 = 0x02 << 5;
/* SR4H = 0, SR4M = 1, SR4L = 1 */
isl6423->reg_4 = 0x03 << 5;
if (isl6423_set_current(fe))
goto exit;
if (isl6423_set_modulation(fe))
goto exit;
fe->ops.release_sec = isl6423_release;
fe->ops.set_voltage = isl6423_set_voltage;
fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
isl6423->verbose = verbose;
return fe;
exit:
kfree(isl6423);
fe->sec_priv = NULL;
return NULL;
}
EXPORT_SYMBOL(isl6423_attach);
MODULE_DESCRIPTION("ISL6423 SEC");
MODULE_AUTHOR("Manu Abraham");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,63 @@
/*
Intersil ISL6423 SEC and LNB Power supply controller
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, 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 __ISL_6423_H
#define __ISL_6423_H
#include <linux/dvb/frontend.h>
enum isl6423_current {
SEC_CURRENT_275m = 0,
SEC_CURRENT_515m,
SEC_CURRENT_635m,
SEC_CURRENT_800m,
};
enum isl6423_curlim {
SEC_CURRENT_LIM_ON = 1,
SEC_CURRENT_LIM_OFF
};
struct isl6423_config {
enum isl6423_current current_max;
enum isl6423_curlim curlim;
u8 addr;
u8 mod_extern;
};
#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct isl6423_config *config);
#else
static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
const struct isl6423_config *config)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_ISL6423 */
#endif /* __ISL_6423_H */

View file

@ -19,6 +19,7 @@
*
*/
#include <asm/div64.h>
#include <linux/dvb/frontend.h>
#include "dvb_math.h"
#include "lgdt3305.h"
@ -496,27 +497,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
nco = if_freq_khz / 10;
#define LGDT3305_64BIT_DIVISION_ENABLED 0
/* FIXME: 64bit division disabled to avoid linking error:
* WARNING: "__udivdi3" [lgdt3305.ko] undefined!
*/
switch (param->u.vsb.modulation) {
case VSB_8:
#if LGDT3305_64BIT_DIVISION_ENABLED
nco <<= 24;
nco /= 625;
#else
nco *= ((1 << 24) / 625);
#endif
do_div(nco, 625);
break;
case QAM_64:
case QAM_256:
#if LGDT3305_64BIT_DIVISION_ENABLED
nco <<= 28;
nco /= 625;
#else
nco *= ((1 << 28) / 625);
#endif
do_div(nco, 625);
break;
default:
return -EINVAL;

View file

@ -37,14 +37,14 @@
} while (0)
static int debug;
static int fake_signal_str;
static int fake_signal_str = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
"Signal strength calculation is slow.(default:off).");
"Signal strength calculation is slow.(default:on).");
/* LGS8GXX internal helper functions */
@ -610,7 +610,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
else
cat = 0;
*signal = cat;
*signal = cat * 65535 / 5;
return 0;
}
@ -630,8 +630,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
if (fake_signal_str) {
if ((t & 0xC0) == 0xC0) {
dprintk("Fake signal strength as 50\n");
*signal = 0x32;
dprintk("Fake signal strength\n");
*signal = 0x7FFF;
} else
*signal = 0;
return 0;

View file

@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
/* override frontend ops */
fe->ops.set_voltage = lnbp21_set_voltage;
fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
return fe;
}

View file

@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
return -EREMOTEIO;
}

View file

@ -879,7 +879,8 @@ static int nxt2002_init(struct dvb_frontend* fe)
/* request the firmware, this will block until someone uploads it */
printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
state->i2c->dev.parent);
printk("nxt2002: Waiting for firmware upload(2)...\n");
if (ret) {
printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
@ -943,7 +944,8 @@ static int nxt2004_init(struct dvb_frontend* fe)
/* request the firmware, this will block until someone uploads it */
printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
state->i2c->dev.parent);
printk("nxt2004: Waiting for firmware upload(2)...\n");
if (ret) {
printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");

View file

@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
}
printk("or51132: Waiting for firmware upload(%s)...\n",
fwname);
ret = request_firmware(&fw, fwname, &state->i2c->dev);
ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
if (ret) {
printk(KERN_WARNING "or51132: No firmware up"
"loaded(timeout or file not found?)\n");

View file

@ -60,8 +60,6 @@
} \
} while (0)
#define dmd_choose(a, b) (demod = STV0900_DEMOD_2 ? b : a))
static int stvdebug;
#define dprintk(args...) \

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
/*
STV0900/0903 Multistandard Broadcast Frontend driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 __STV090x_H
#define __STV090x_H
enum stv090x_demodulator {
STV090x_DEMODULATOR_0 = 1,
STV090x_DEMODULATOR_1
};
enum stv090x_device {
STV0903 = 0,
STV0900,
};
enum stv090x_mode {
STV090x_DUAL = 0,
STV090x_SINGLE
};
enum stv090x_tsmode {
STV090x_TSMODE_SERIAL_PUNCTURED = 1,
STV090x_TSMODE_SERIAL_CONTINUOUS,
STV090x_TSMODE_PARALLEL_PUNCTURED,
STV090x_TSMODE_DVBCI
};
enum stv090x_clkmode {
STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
};
enum stv090x_i2crpt {
STV090x_RPTLEVEL_256 = 0,
STV090x_RPTLEVEL_128 = 1,
STV090x_RPTLEVEL_64 = 2,
STV090x_RPTLEVEL_32 = 3,
STV090x_RPTLEVEL_16 = 4,
STV090x_RPTLEVEL_8 = 5,
STV090x_RPTLEVEL_4 = 6,
STV090x_RPTLEVEL_2 = 7,
};
struct stv090x_config {
enum stv090x_device device;
enum stv090x_mode demod_mode;
enum stv090x_clkmode clk_mode;
u32 xtal; /* default: 8000000 */
u8 address; /* default: 0x68 */
u32 ref_clk; /* default: 16000000 FIXME to tuner config */
u8 ts1_mode;
u8 ts2_mode;
enum stv090x_i2crpt repeater_level;
int (*tuner_init) (struct dvb_frontend *fe);
int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk);
int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
};
#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
struct i2c_adapter *i2c,
enum stv090x_demodulator demod);
#else
static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
struct i2c_adapter *i2c,
enum stv090x_demodulator demod)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_STV090x */
#endif /* __STV090x_H */

View file

@ -0,0 +1,269 @@
/*
STV0900/0903 Multistandard Broadcast Frontend driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 __STV090x_PRIV_H
#define __STV090x_PRIV_H
#include "dvb_frontend.h"
#define FE_ERROR 0
#define FE_NOTICE 1
#define FE_INFO 2
#define FE_DEBUG 3
#define FE_DEBUGREG 4
#define dprintk(__y, __z, format, arg...) do { \
if (__z) { \
if ((verbose > FE_ERROR) && (verbose > __y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_NOTICE) && (verbose > __y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_INFO) && (verbose > __y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_DEBUG) && (verbose > __y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (verbose > __y) \
printk(format, ##arg); \
} \
} while (0)
#define STV090x_READ_DEMOD(__state, __reg) (( \
(__state)->demod == STV090x_DEMODULATOR_1) ? \
stv090x_read_reg(__state, STV090x_P2_##__reg) : \
stv090x_read_reg(__state, STV090x_P1_##__reg))
#define STV090x_WRITE_DEMOD(__state, __reg, __data) (( \
(__state)->demod == STV090x_DEMODULATOR_1) ? \
stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
#define STV090x_ADDR_OFFST(__state, __x) (( \
(__state->demod) == STV090x_DEMODULATOR_1) ? \
STV090x_P1_##__x : \
STV090x_P2_##__x)
#define STV090x_SETFIELD(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
STV090x_OFFST_##bitf))) | \
(val << STV090x_OFFST_##bitf))
#define STV090x_GETFIELD(val, bitf) ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
#define STV090x_SETFIELD_Px(mask, bitf, val) (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
STV090x_OFFST_Px_##bitf))) | \
(val << STV090x_OFFST_Px_##bitf))
#define STV090x_GETFIELD_Px(val, bitf) ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
#define MAKEWORD16(__a, __b) (((__a) << 8) | (__b))
#define MSB(__x) ((__x >> 8) & 0xff)
#define LSB(__x) (__x & 0xff)
#define STV090x_IQPOWER_THRESHOLD 30
#define STV090x_SEARCH_AGC2_TH_CUT20 700
#define STV090x_SEARCH_AGC2_TH_CUT30 1200
#define STV090x_SEARCH_AGC2_TH(__ver) \
((__ver <= 0x20) ? \
STV090x_SEARCH_AGC2_TH_CUT20 : \
STV090x_SEARCH_AGC2_TH_CUT30)
enum stv090x_signal_state {
STV090x_NOCARRIER,
STV090x_NODATA,
STV090x_DATAOK,
STV090x_RANGEOK,
STV090x_OUTOFRANGE
};
enum stv090x_fec {
STV090x_PR12 = 0,
STV090x_PR23,
STV090x_PR34,
STV090x_PR45,
STV090x_PR56,
STV090x_PR67,
STV090x_PR78,
STV090x_PR89,
STV090x_PR910,
STV090x_PRERR
};
enum stv090x_modulation {
STV090x_QPSK,
STV090x_8PSK,
STV090x_16APSK,
STV090x_32APSK,
STV090x_UNKNOWN
};
enum stv090x_frame {
STV090x_LONG_FRAME,
STV090x_SHORT_FRAME
};
enum stv090x_pilot {
STV090x_PILOTS_OFF,
STV090x_PILOTS_ON
};
enum stv090x_rolloff {
STV090x_RO_35,
STV090x_RO_25,
STV090x_RO_20
};
enum stv090x_inversion {
STV090x_IQ_AUTO,
STV090x_IQ_NORMAL,
STV090x_IQ_SWAP
};
enum stv090x_modcod {
STV090x_DUMMY_PLF = 0,
STV090x_QPSK_14,
STV090x_QPSK_13,
STV090x_QPSK_25,
STV090x_QPSK_12,
STV090x_QPSK_35,
STV090x_QPSK_23,
STV090x_QPSK_34,
STV090x_QPSK_45,
STV090x_QPSK_56,
STV090x_QPSK_89,
STV090x_QPSK_910,
STV090x_8PSK_35,
STV090x_8PSK_23,
STV090x_8PSK_34,
STV090x_8PSK_56,
STV090x_8PSK_89,
STV090x_8PSK_910,
STV090x_16APSK_23,
STV090x_16APSK_34,
STV090x_16APSK_45,
STV090x_16APSK_56,
STV090x_16APSK_89,
STV090x_16APSK_910,
STV090x_32APSK_34,
STV090x_32APSK_45,
STV090x_32APSK_56,
STV090x_32APSK_89,
STV090x_32APSK_910,
STV090x_MODCODE_UNKNOWN
};
enum stv090x_search {
STV090x_SEARCH_DSS = 0,
STV090x_SEARCH_DVBS1,
STV090x_SEARCH_DVBS2,
STV090x_SEARCH_AUTO
};
enum stv090x_algo {
STV090x_BLIND_SEARCH,
STV090x_COLD_SEARCH,
STV090x_WARM_SEARCH
};
enum stv090x_delsys {
STV090x_ERROR = 0,
STV090x_DVBS1 = 1,
STV090x_DVBS2,
STV090x_DSS
};
struct stv090x_long_frame_crloop {
enum stv090x_modcod modcod;
u8 crl_pilots_on_2;
u8 crl_pilots_off_2;
u8 crl_pilots_on_5;
u8 crl_pilots_off_5;
u8 crl_pilots_on_10;
u8 crl_pilots_off_10;
u8 crl_pilots_on_20;
u8 crl_pilots_off_20;
u8 crl_pilots_on_30;
u8 crl_pilots_off_30;
};
struct stv090x_short_frame_crloop {
enum stv090x_modulation modulation;
u8 crl_2; /* SR < 3M */
u8 crl_5; /* 3 < SR <= 7M */
u8 crl_10; /* 7 < SR <= 15M */
u8 crl_20; /* 10 < SR <= 25M */
u8 crl_30; /* 10 < SR <= 45M */
};
struct stv090x_reg {
u16 addr;
u8 data;
};
struct stv090x_tab {
s32 real;
s32 read;
};
struct stv090x_state {
enum stv090x_device device;
enum stv090x_demodulator demod;
enum stv090x_mode demod_mode;
u32 dev_ver;
struct i2c_adapter *i2c;
const struct stv090x_config *config;
struct dvb_frontend frontend;
u32 *verbose; /* Cached module verbosity */
enum stv090x_delsys delsys;
enum stv090x_fec fec;
enum stv090x_modulation modulation;
enum stv090x_modcod modcod;
enum stv090x_search search_mode;
enum stv090x_frame frame_len;
enum stv090x_pilot pilots;
enum stv090x_rolloff rolloff;
enum stv090x_inversion inversion;
enum stv090x_algo algo;
u32 frequency;
u32 srate;
s32 mclk; /* Masterclock Divider factor */
s32 tuner_bw;
u32 tuner_refclk;
s32 search_range;
s32 DemodTimeout;
s32 FecTimeout;
};
#endif /* __STV090x_PRIV_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,373 @@
/*
STV6110(A) Silicon tuner driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include "dvb_frontend.h"
#include "stv6110x_reg.h"
#include "stv6110x.h"
#include "stv6110x_priv.h"
static unsigned int verbose;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "Set Verbosity level");
static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
{
int ret;
const struct stv6110x_config *config = stv6110x->config;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{ .addr = config->addr, .flags = 0, .buf = b0, .len = 1 },
{ .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
};
ret = i2c_transfer(stv6110x->i2c, msg, 2);
if (ret != 2) {
dprintk(FE_ERROR, 1, "I/O Error");
return -EREMOTEIO;
}
*data = b1[0];
return 0;
}
static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
{
int ret;
const struct stv6110x_config *config = stv6110x->config;
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
ret = i2c_transfer(stv6110x->i2c, &msg, 1);
if (ret != 1) {
dprintk(FE_ERROR, 1, "I/O Error");
return -EREMOTEIO;
}
return 0;
}
static int stv6110x_init(struct dvb_frontend *fe)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
int ret;
u8 i;
for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
if (ret < 0) {
dprintk(FE_ERROR, 1, "Initialization failed");
return -1;
}
}
return 0;
}
static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
u32 rDiv, divider;
s32 pVal, pCalc, rDivOpt = 0;
u8 i;
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
if (frequency <= 1023000) {
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
pVal = 40;
} else if (frequency <= 1300000) {
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
pVal = 40;
} else if (frequency <= 2046000) {
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
pVal = 20;
} else {
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
pVal = 20;
}
for (rDiv = 0; rDiv <= 3; rDiv++) {
pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
rDivOpt = rDiv;
}
divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
divider = (divider + 5) / 10;
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
/* VCO Auto calibration */
STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
for (i = 0; i < TRIALS; i++) {
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
break;
msleep(1);
}
return 0;
}
static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
*frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
*frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
*frequency >>= 2;
return 0;
}
static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
u32 halfbw;
u8 i;
halfbw = bandwidth >> 1;
if (halfbw > 36000000)
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
else if (halfbw < 5000000)
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
else
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
for (i = 0; i < TRIALS; i++) {
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
break;
msleep(1);
}
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
return 0;
}
static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
*bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
return 0;
}
static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
/* setup divider */
switch (refclock) {
default:
case 1:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
break;
case 2:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
break;
case 4:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
break;
case 8:
case 0:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
break;
}
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
return 0;
}
static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
*gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
return 0;
}
static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
return 0;
}
static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
int ret;
switch (mode) {
case TUNER_SLEEP:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
break;
case TUNER_WAKE:
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
break;
}
ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
if (ret < 0) {
dprintk(FE_ERROR, 1, "I/O Error");
return -EIO;
}
return 0;
}
static int stv6110x_sleep(struct dvb_frontend *fe)
{
return stv6110x_set_mode(fe, TUNER_SLEEP);
}
static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
*status = TUNER_PHASELOCKED;
else
*status = 0;
return 0;
}
static int stv6110x_release(struct dvb_frontend *fe)
{
struct stv6110x_state *stv6110x = fe->tuner_priv;
fe->tuner_priv = NULL;
kfree(stv6110x);
return 0;
}
static struct dvb_tuner_ops stv6110x_ops = {
.info = {
.name = "STV6110(A) Silicon Tuner",
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0,
},
.init = stv6110x_init,
.sleep = stv6110x_sleep,
.release = stv6110x_release
};
static struct stv6110x_devctl stv6110x_ctl = {
.tuner_init = stv6110x_init,
.tuner_set_mode = stv6110x_set_mode,
.tuner_set_frequency = stv6110x_set_frequency,
.tuner_get_frequency = stv6110x_get_frequency,
.tuner_set_bandwidth = stv6110x_set_bandwidth,
.tuner_get_bandwidth = stv6110x_get_bandwidth,
.tuner_set_bbgain = stv6110x_set_bbgain,
.tuner_get_bbgain = stv6110x_get_bbgain,
.tuner_set_refclk = stv6110x_set_refclock,
.tuner_get_status = stv6110x_get_status,
};
struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{
struct stv6110x_state *stv6110x;
stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
if (stv6110x == NULL)
goto error;
stv6110x->i2c = i2c;
stv6110x->config = config;
stv6110x->devctl = &stv6110x_ctl;
fe->tuner_priv = stv6110x;
fe->ops.tuner_ops = stv6110x_ops;
printk("%s: Attaching STV6110x \n", __func__);
return stv6110x->devctl;
error:
kfree(stv6110x);
return NULL;
}
EXPORT_SYMBOL(stv6110x_attach);
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("STV6110x Silicon tuner");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,71 @@
/*
STV6110(A) Silicon tuner driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 __STV6110x_H
#define __STV6110x_H
struct stv6110x_config {
u8 addr;
u32 refclk;
};
enum tuner_mode {
TUNER_SLEEP = 1,
TUNER_WAKE,
};
enum tuner_status {
TUNER_PHASELOCKED = 1,
};
struct stv6110x_devctl {
int (*tuner_init) (struct dvb_frontend *fe);
int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk);
int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
};
#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c);
#else
static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
const struct stv6110x_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif /* CONFIG_DVB_STV6110x */
#endif /* __STV6110x_H */

View file

@ -0,0 +1,75 @@
/*
STV6110(A) Silicon tuner driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 __STV6110x_PRIV_H
#define __STV6110x_PRIV_H
#define FE_ERROR 0
#define FE_NOTICE 1
#define FE_INFO 2
#define FE_DEBUG 3
#define FE_DEBUGREG 4
#define dprintk(__y, __z, format, arg...) do { \
if (__z) { \
if ((verbose > FE_ERROR) && (verbose > __y)) \
printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_NOTICE) && (verbose > __y)) \
printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_INFO) && (verbose > __y)) \
printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
else if ((verbose > FE_DEBUG) && (verbose > __y)) \
printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
} else { \
if (verbose > __y) \
printk(format, ##arg); \
} \
} while (0)
#define STV6110x_SETFIELD(mask, bitf, val) \
(mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) << \
STV6110x_OFFST_##bitf))) | \
(val << STV6110x_OFFST_##bitf))
#define STV6110x_GETFIELD(bitf, val) \
((val >> STV6110x_OFFST_##bitf) & \
((1 << STV6110x_WIDTH_##bitf) - 1))
#define MAKEWORD16(a, b) (((a) << 8) | (b))
#define LSB(x) ((x & 0xff))
#define MSB(y) ((y >> 8) & 0xff)
#define TRIALS 10
#define R_DIV(__div) (1 << (__div + 1))
#define REFCLOCK_kHz (stv6110x->config->refclk / 1000)
#define REFCLOCK_MHz (stv6110x->config->refclk / 1000000)
struct stv6110x_state {
struct i2c_adapter *i2c;
const struct stv6110x_config *config;
struct stv6110x_devctl *devctl;
};
#endif /* __STV6110x_PRIV_H */

View file

@ -0,0 +1,82 @@
/*
STV6110(A) Silicon tuner driver
Copyright (C) Manu Abraham <abraham.manu@gmail.com>
Copyright (C) ST Microelectronics
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 __STV6110x_REG_H
#define __STV6110x_REG_H
#define STV6110x_CTRL1 0x00
#define STV6110x_OFFST_CTRL1_K 3
#define STV6110x_WIDTH_CTRL1_K 5
#define STV6110x_OFFST_CTRL1_LPT 2
#define STV6110x_WIDTH_CTRL1_LPT 1
#define STV6110x_OFFST_CTRL1_RX 1
#define STV6110x_WIDTH_CTRL1_RX 1
#define STV6110x_OFFST_CTRL1_SYN 0
#define STV6110x_WIDTH_CTRL1_SYN 1
#define STV6110x_CTRL2 0x01
#define STV6110x_OFFST_CTRL2_CO_DIV 6
#define STV6110x_WIDTH_CTRL2_CO_DIV 2
#define STV6110x_OFFST_CTRL2_RSVD 5
#define STV6110x_WIDTH_CTRL2_RSVD 1
#define STV6110x_OFFST_CTRL2_REFOUT_SEL 4
#define STV6110x_WIDTH_CTRL2_REFOUT_SEL 1
#define STV6110x_OFFST_CTRL2_BBGAIN 0
#define STV6110x_WIDTH_CTRL2_BBGAIN 4
#define STV6110x_TNG0 0x02
#define STV6110x_OFFST_TNG0_N_DIV_7_0 0
#define STV6110x_WIDTH_TNG0_N_DIV_7_0 8
#define STV6110x_TNG1 0x03
#define STV6110x_OFFST_TNG1_R_DIV 6
#define STV6110x_WIDTH_TNG1_R_DIV 2
#define STV6110x_OFFST_TNG1_PRESC32_ON 5
#define STV6110x_WIDTH_TNG1_PRESC32_ON 1
#define STV6110x_OFFST_TNG1_DIV4SEL 4
#define STV6110x_WIDTH_TNG1_DIV4SEL 1
#define STV6110x_OFFST_TNG1_N_DIV_11_8 0
#define STV6110x_WIDTH_TNG1_N_DIV_11_8 4
#define STV6110x_CTRL3 0x04
#define STV6110x_OFFST_CTRL3_DCLOOP_OFF 7
#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF 1
#define STV6110x_OFFST_CTRL3_RCCLK_OFF 6
#define STV6110x_WIDTH_CTRL3_RCCLK_OFF 1
#define STV6110x_OFFST_CTRL3_ICP 5
#define STV6110x_WIDTH_CTRL3_ICP 1
#define STV6110x_OFFST_CTRL3_CF 0
#define STV6110x_WIDTH_CTRL3_CF 5
#define STV6110x_STAT1 0x05
#define STV6110x_OFFST_STAT1_CALVCO_STRT 2
#define STV6110x_WIDTH_STAT1_CALVCO_STRT 1
#define STV6110x_OFFST_STAT1_CALRC_STRT 1
#define STV6110x_WIDTH_STAT1_CALRC_STRT 1
#define STV6110x_OFFST_STAT1_LOCK 0
#define STV6110x_WIDTH_STAT1_LOCK 1
#define STV6110x_STAT2 0x06
#define STV6110x_STAT3 0x07
#endif /* __STV6110x_REG_H */

View file

@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
#include "tda10048.h"
@ -138,11 +139,20 @@ struct tda10048_state {
struct i2c_adapter *i2c;
/* configuration settings */
const struct tda10048_config *config;
/* We'll cache and update the attach config settings */
struct tda10048_config config;
struct dvb_frontend frontend;
int fwloaded;
u32 freq_if_hz;
u32 xtal_hz;
u32 pll_mfactor;
u32 pll_nfactor;
u32 pll_pfactor;
u32 sample_freq;
enum fe_bandwidth bandwidth;
};
static struct init_tab {
@ -192,12 +202,26 @@ static struct init_tab {
{ TDA10048_CONF_C4_2, 0x04 },
};
static struct pll_tab {
u32 clk_freq_khz;
u32 if_freq_khz;
u8 m, n, p;
} pll_tab[] = {
{ TDA10048_CLK_4000, TDA10048_IF_36130, 10, 0, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_3300, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_3500, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_4000, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_4300, 10, 3, 0 },
{ TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
};
static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
{
struct tda10048_config *config = &state->config;
int ret;
u8 buf[] = { reg, data };
struct i2c_msg msg = {
.addr = state->config->demod_address,
.addr = config->demod_address,
.flags = 0, .buf = buf, .len = 2 };
dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
@ -212,13 +236,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
{
struct tda10048_config *config = &state->config;
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address,
{ .addr = config->demod_address,
.flags = 0, .buf = b0, .len = 1 },
{ .addr = state->config->demod_address,
{ .addr = config->demod_address,
.flags = I2C_M_RD, .buf = b1, .len = 1 } };
dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
@ -235,6 +260,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
const u8 *data, u16 len)
{
struct tda10048_config *config = &state->config;
int ret = -EREMOTEIO;
struct i2c_msg msg;
u8 *buf;
@ -250,7 +276,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
*buf = reg;
memcpy(buf + 1, data, len);
msg.addr = state->config->demod_address;
msg.addr = config->demod_address;
msg.flags = 0;
msg.buf = buf;
msg.len = len + 1;
@ -271,14 +297,206 @@ error:
return ret;
}
static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
u32 if_hz)
{
struct tda10048_state *state = fe->demodulator_priv;
u64 t;
dprintk(1, "%s()\n", __func__);
if (sample_freq_hz == 0)
return -EINVAL;
if (if_hz < (sample_freq_hz / 2)) {
/* PHY2 = (if2/fs) * 2^15 */
t = if_hz;
t *= 10;
t *= 32768;
do_div(t, sample_freq_hz);
t += 5;
do_div(t, 10);
} else {
/* PHY2 = ((IF1-fs)/fs) * 2^15 */
t = sample_freq_hz - if_hz;
t *= 10;
t *= 32768;
do_div(t, sample_freq_hz);
t += 5;
do_div(t, 10);
t = ~t + 1;
}
tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
return 0;
}
static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
u32 bw)
{
struct tda10048_state *state = fe->demodulator_priv;
u64 t, z;
u32 b = 8000000;
dprintk(1, "%s()\n", __func__);
if (sample_freq_hz == 0)
return -EINVAL;
if (bw == BANDWIDTH_6_MHZ)
b = 6000000;
else
if (bw == BANDWIDTH_7_MHZ)
b = 7000000;
/* WREF = (B / (7 * fs)) * 2^31 */
t = b * 10;
/* avoid warning: this decimal constant is unsigned only in ISO C90 */
/* t *= 2147483648 on 32bit platforms */
t *= (2048 * 1024);
t *= 1024;
z = 7 * sample_freq_hz;
do_div(t, z);
t += 5;
do_div(t, 10);
tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
return 0;
}
static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
u32 bw)
{
struct tda10048_state *state = fe->demodulator_priv;
u64 t;
u32 b = 8000000;
dprintk(1, "%s()\n", __func__);
if (sample_freq_hz == 0)
return -EINVAL;
if (bw == BANDWIDTH_6_MHZ)
b = 6000000;
else
if (bw == BANDWIDTH_7_MHZ)
b = 7000000;
/* INVWREF = ((7 * fs) / B) * 2^5 */
t = sample_freq_hz;
t *= 7;
t *= 32;
t *= 10;
do_div(t, b);
t += 5;
do_div(t, 10);
tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
return 0;
}
static int tda10048_set_bandwidth(struct dvb_frontend *fe,
enum fe_bandwidth bw)
{
struct tda10048_state *state = fe->demodulator_priv;
dprintk(1, "%s(bw=%d)\n", __func__, bw);
/* Bandwidth setting may need to be adjusted */
switch (bw) {
case BANDWIDTH_6_MHZ:
case BANDWIDTH_7_MHZ:
case BANDWIDTH_8_MHZ:
tda10048_set_wref(fe, state->sample_freq, bw);
tda10048_set_invwref(fe, state->sample_freq, bw);
break;
default:
printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
return -EINVAL;
}
state->bandwidth = bw;
return 0;
}
static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
int i;
u32 if_freq_khz;
dprintk(1, "%s(bw = %d)\n", __func__, bw);
/* based on target bandwidth and clk we calculate pll factors */
switch (bw) {
case BANDWIDTH_6_MHZ:
if_freq_khz = config->dtv6_if_freq_khz;
break;
case BANDWIDTH_7_MHZ:
if_freq_khz = config->dtv7_if_freq_khz;
break;
case BANDWIDTH_8_MHZ:
if_freq_khz = config->dtv8_if_freq_khz;
break;
default:
printk(KERN_ERR "%s() no default\n", __func__);
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
(pll_tab[i].if_freq_khz == if_freq_khz)) {
state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
state->pll_mfactor = pll_tab[i].m;
state->pll_nfactor = pll_tab[i].n;
state->pll_pfactor = pll_tab[i].p;
break;
}
}
if (i == ARRAY_SIZE(pll_tab)) {
printk(KERN_ERR "%s() Incorrect attach settings\n",
__func__);
return -EINVAL;
}
dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
/* Calculate the sample frequency */
state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
state->sample_freq /= (state->pll_nfactor + 1);
state->sample_freq /= (state->pll_pfactor + 4);
dprintk(1, "- sample_freq = %d\n", state->sample_freq);
/* Update the I/F */
tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
return 0;
}
static int tda10048_firmware_upload(struct dvb_frontend *fe)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
const struct firmware *fw;
int ret;
int pos = 0;
int cnt;
u8 wlen = state->config->fwbulkwritelen;
u8 wlen = config->fwbulkwritelen;
if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
wlen = TDA10048_BULKWRITE_200;
@ -289,7 +507,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
TDA10048_DEFAULT_FIRMWARE);
ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
&state->i2c->dev);
state->i2c->dev.parent);
if (ret) {
printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
__func__);
@ -484,8 +702,12 @@ static int tda10048_get_tps(struct tda10048_state *state,
static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
dprintk(1, "%s(%d)\n", __func__, enable);
if (config->disable_gate_access)
return 0;
if (enable)
return tda10048_writereg(state, TDA10048_CONF_C4_1,
tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
@ -523,6 +745,12 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
/* Update the I/F pll's if the bandwidth changes */
if (p->u.ofdm.bandwidth != state->bandwidth) {
tda10048_set_if(fe, p->u.ofdm.bandwidth);
tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth);
}
if (fe->ops.tuner_ops.set_params) {
if (fe->ops.i2c_gate_ctrl)
@ -544,6 +772,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
static int tda10048_init(struct dvb_frontend *fe)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
int ret = 0, i;
dprintk(1, "%s()\n", __func__);
@ -556,10 +785,14 @@ static int tda10048_init(struct dvb_frontend *fe)
ret = tda10048_firmware_upload(fe);
/* Set either serial or parallel */
tda10048_output_mode(fe, state->config->output_mode);
tda10048_output_mode(fe, config->output_mode);
/* set inversion */
tda10048_set_inversion(fe, state->config->inversion);
/* Set inversion */
tda10048_set_inversion(fe, config->inversion);
/* Establish default RF values */
tda10048_set_if(fe, BANDWIDTH_8_MHZ);
tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
/* Ensure we leave the gate closed */
tda10048_i2c_gate_ctrl(fe, 0);
@ -812,6 +1045,45 @@ static void tda10048_release(struct dvb_frontend *fe)
kfree(state);
}
static void tda10048_establish_defaults(struct dvb_frontend *fe)
{
struct tda10048_state *state = fe->demodulator_priv;
struct tda10048_config *config = &state->config;
/* Validate/default the config */
if (config->dtv6_if_freq_khz == 0) {
config->dtv6_if_freq_khz = TDA10048_IF_4300;
printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
"is not set (defaulting to %d)\n",
__func__,
config->dtv6_if_freq_khz);
}
if (config->dtv7_if_freq_khz == 0) {
config->dtv7_if_freq_khz = TDA10048_IF_4300;
printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
"is not set (defaulting to %d)\n",
__func__,
config->dtv7_if_freq_khz);
}
if (config->dtv8_if_freq_khz == 0) {
config->dtv8_if_freq_khz = TDA10048_IF_4300;
printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
"is not set (defaulting to %d)\n",
__func__,
config->dtv8_if_freq_khz);
}
if (config->clk_freq_khz == 0) {
config->clk_freq_khz = TDA10048_CLK_16000;
printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
"is not set (defaulting to %d)\n",
__func__,
config->clk_freq_khz);
}
}
static struct dvb_frontend_ops tda10048_ops;
struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
@ -826,10 +1098,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
if (state == NULL)
goto error;
/* setup the state */
state->config = config;
/* setup the state and clone the config */
memcpy(&state->config, config, sizeof(*config));
state->i2c = i2c;
state->fwloaded = 0;
state->bandwidth = BANDWIDTH_8_MHZ;
/* check if the demod is present */
if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@ -840,6 +1113,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* Establish any defaults the the user didn't pass */
tda10048_establish_defaults(&state->frontend);
/* Set the xtal and freq defaults */
if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
goto error;
/* Default bandwidth */
if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
goto error;
/* Leave the gate closed */
tda10048_i2c_gate_ctrl(&state->frontend, 0);

View file

@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -43,6 +43,25 @@ struct tda10048_config {
#define TDA10048_INVERSION_OFF 0
#define TDA10048_INVERSION_ON 1
u8 inversion;
#define TDA10048_IF_3300 3300
#define TDA10048_IF_3500 3500
#define TDA10048_IF_3800 3800
#define TDA10048_IF_4000 4000
#define TDA10048_IF_4300 4300
#define TDA10048_IF_4500 4500
#define TDA10048_IF_4750 4750
#define TDA10048_IF_36130 36130
u16 dtv6_if_freq_khz;
u16 dtv7_if_freq_khz;
u16 dtv8_if_freq_khz;
#define TDA10048_CLK_4000 4000
#define TDA10048_CLK_16000 16000
u16 clk_freq_khz;
/* Disable I2C gate access */
u8 disable_gate_access;
};
#if defined(CONFIG_DVB_TDA10048) || \

View file

@ -1,4 +1,4 @@
sms1xxx-objs := smscoreapi.o sms-cards.o
sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o

View file

@ -18,6 +18,7 @@
*/
#include "sms-cards.h"
#include "smsir.h"
static int sms_dbg;
module_param_named(cards_dbg, sms_dbg, int, 0644);
@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = {
[SMS1XXX_BOARD_SIANO_STELLAR] = {
.name = "Siano Stellar Digital Receiver",
.type = SMS_STELLAR,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_NOVA_A] = {
.name = "Siano Nova A Digital Receiver",
.type = SMS_NOVA_A0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_NOVA_B] = {
.name = "Siano Nova B Digital Receiver",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
},
[SMS1XXX_BOARD_SIANO_VEGA] = {
.name = "Siano Vega Digital Receiver",
@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = {
.name = "Hauppauge WinTV MiniStick",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
.board_cfg.led1 = 28,
.led_power = 26,
.led_lo = 27,
.led_hi = 28,
@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = {
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = 29,
.board_cfg.foreign_lna0_ctrl = 29,
.rf_switch = 17,
.board_cfg.rf_switch_uhf = 17,
},
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
.name = "Hauppauge WinTV MiniCard",
@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = {
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
.lna_ctrl = -1,
},
[SMS1XXX_BOARD_SIANO_NICE] = {
/* 11 */
.name = "Siano Nice Digital Receiver",
.type = SMS_NOVA_B0,
},
[SMS1XXX_BOARD_SIANO_VENICE] = {
/* 12 */
.name = "Siano Venice Digital Receiver",
.type = SMS_VEGA,
},
};
struct sms_board *sms_get_board(int id)
@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id)
return &sms_boards[id];
}
EXPORT_SYMBOL_GPL(sms_get_board);
static inline void sms_gpio_assign_11xx_default_led_config(
struct smscore_gpio_config *pGpioConfig) {
pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
pGpioConfig->InputCharacteristics =
SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
}
int sms_board_event(struct smscore_device_t *coredev,
enum SMS_BOARD_EVENTS gevent) {
int board_id = smscore_get_board_id(coredev);
struct sms_board *board = sms_get_board(board_id);
struct smscore_gpio_config MyGpioConfig;
sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
switch (gevent) {
case BOARD_EVENT_POWER_INIT: /* including hotplug */
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
/* set I/O and turn off all LEDs */
smscore_gpio_configure(coredev,
board->board_cfg.leds_power,
&MyGpioConfig);
smscore_gpio_set_level(coredev,
board->board_cfg.leds_power, 0);
smscore_gpio_configure(coredev, board->board_cfg.led0,
&MyGpioConfig);
smscore_gpio_set_level(coredev,
board->board_cfg.led0, 0);
smscore_gpio_configure(coredev, board->board_cfg.led1,
&MyGpioConfig);
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
/* set I/O and turn off LNA */
smscore_gpio_configure(coredev,
board->board_cfg.foreign_lna0_ctrl,
&MyGpioConfig);
smscore_gpio_set_level(coredev,
board->board_cfg.foreign_lna0_ctrl,
0);
break;
}
break; /* BOARD_EVENT_BIND */
case BOARD_EVENT_POWER_SUSPEND:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.leds_power, 0);
smscore_gpio_set_level(coredev,
board->board_cfg.led0, 0);
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
smscore_gpio_set_level(coredev,
board->board_cfg.foreign_lna0_ctrl,
0);
break;
}
break; /* BOARD_EVENT_POWER_SUSPEND */
case BOARD_EVENT_POWER_RESUME:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.leds_power, 1);
smscore_gpio_set_level(coredev,
board->board_cfg.led0, 1);
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
smscore_gpio_set_level(coredev,
board->board_cfg.foreign_lna0_ctrl,
1);
break;
}
break; /* BOARD_EVENT_POWER_RESUME */
case BOARD_EVENT_BIND:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.leds_power, 1);
smscore_gpio_set_level(coredev,
board->board_cfg.led0, 1);
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
smscore_gpio_set_level(coredev,
board->board_cfg.foreign_lna0_ctrl,
1);
break;
}
break; /* BOARD_EVENT_BIND */
case BOARD_EVENT_SCAN_PROG:
break; /* BOARD_EVENT_SCAN_PROG */
case BOARD_EVENT_SCAN_COMP:
break; /* BOARD_EVENT_SCAN_COMP */
case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
case BOARD_EVENT_FE_LOCK:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 1);
break;
}
break; /* BOARD_EVENT_FE_LOCK */
case BOARD_EVENT_FE_UNLOCK:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
}
break; /* BOARD_EVENT_FE_UNLOCK */
case BOARD_EVENT_DEMOD_LOCK:
break; /* BOARD_EVENT_DEMOD_LOCK */
case BOARD_EVENT_DEMOD_UNLOCK:
break; /* BOARD_EVENT_DEMOD_UNLOCK */
case BOARD_EVENT_RECEPTION_MAX_4:
break; /* BOARD_EVENT_RECEPTION_MAX_4 */
case BOARD_EVENT_RECEPTION_3:
break; /* BOARD_EVENT_RECEPTION_3 */
case BOARD_EVENT_RECEPTION_2:
break; /* BOARD_EVENT_RECEPTION_2 */
case BOARD_EVENT_RECEPTION_1:
break; /* BOARD_EVENT_RECEPTION_1 */
case BOARD_EVENT_RECEPTION_LOST_0:
break; /* BOARD_EVENT_RECEPTION_LOST_0 */
case BOARD_EVENT_MULTIPLEX_OK:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 1);
break;
}
break; /* BOARD_EVENT_MULTIPLEX_OK */
case BOARD_EVENT_MULTIPLEX_ERRORS:
switch (board_id) {
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
smscore_gpio_set_level(coredev,
board->board_cfg.led1, 0);
break;
}
break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
default:
sms_err("Unknown SMS board event");
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(sms_board_event);
static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
{
int lvl, ret;
u32 gpio;
struct smscore_gpio_config gpioconfig = {
struct smscore_config_gpio gpioconfig = {
.direction = SMS_GPIO_DIRECTION_OUTPUT,
.pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
.inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,

View file

@ -22,6 +22,7 @@
#include <linux/usb.h>
#include "smscoreapi.h"
#include "smsir.h"
#define SMS_BOARD_UNKNOWN 0
#define SMS1XXX_BOARD_SIANO_STELLAR 1
@ -34,10 +35,47 @@
#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
#define SMS1XXX_BOARD_SIANO_NICE 11
#define SMS1XXX_BOARD_SIANO_VENICE 12
struct sms_board_gpio_cfg {
int lna_vhf_exist;
int lna_vhf_ctrl;
int lna_uhf_exist;
int lna_uhf_ctrl;
int lna_uhf_d_ctrl;
int lna_sband_exist;
int lna_sband_ctrl;
int lna_sband_d_ctrl;
int foreign_lna0_ctrl;
int foreign_lna1_ctrl;
int foreign_lna2_ctrl;
int rf_switch_vhf;
int rf_switch_uhf;
int rf_switch_sband;
int leds_power;
int led0;
int led1;
int led2;
int led3;
int led4;
int ir;
int eeprom_wp;
int mrc_sense;
int mrc_pdn_resetn;
int mrc_gp0; /* mrcs spi int */
int mrc_gp1;
int mrc_gp2;
int mrc_gp3;
int mrc_gp4;
int host_spi_gsp_ts_int;
};
struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
struct sms_board_gpio_cfg board_cfg;
enum ir_kb_type ir_kb_type;
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
@ -45,6 +83,32 @@ struct sms_board {
struct sms_board *sms_get_board(int id);
extern struct smscore_device_t *coredev;
enum SMS_BOARD_EVENTS {
BOARD_EVENT_POWER_INIT,
BOARD_EVENT_POWER_SUSPEND,
BOARD_EVENT_POWER_RESUME,
BOARD_EVENT_BIND,
BOARD_EVENT_SCAN_PROG,
BOARD_EVENT_SCAN_COMP,
BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
BOARD_EVENT_FE_LOCK,
BOARD_EVENT_FE_UNLOCK,
BOARD_EVENT_DEMOD_LOCK,
BOARD_EVENT_DEMOD_UNLOCK,
BOARD_EVENT_RECEPTION_MAX_4,
BOARD_EVENT_RECEPTION_3,
BOARD_EVENT_RECEPTION_2,
BOARD_EVENT_RECEPTION_1,
BOARD_EVENT_RECEPTION_LOST_0,
BOARD_EVENT_MULTIPLEX_OK,
BOARD_EVENT_MULTIPLEX_ERRORS
};
int sms_board_event(struct smscore_device_t *coredev,
enum SMS_BOARD_EVENTS gevent);
int sms_board_setup(struct smscore_device_t *coredev);
#define SMS_LED_OFF 0

View file

@ -30,9 +30,13 @@
#include <linux/io.h>
#include <linux/firmware.h>
#include <linux/wait.h>
#include <asm/byteorder.h>
#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsir.h"
#include "smsendian.h"
static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
@ -58,42 +62,6 @@ struct smscore_client_t {
onremove_t onremove_handler;
};
struct smscore_device_t {
struct list_head entry;
struct list_head clients;
struct list_head subclients;
spinlock_t clientslock;
struct list_head buffers;
spinlock_t bufferslock;
int num_buffers;
void *common_buffer;
int common_buffer_size;
dma_addr_t common_buffer_phys;
void *context;
struct device *device;
char devpath[32];
unsigned long device_flags;
setmode_t setmode_handler;
detectmode_t detectmode_handler;
sendrequest_t sendrequest_handler;
preload_t preload_handler;
postload_t postload_handler;
int mode, modes_supported;
struct completion version_ex_done, data_download_done, trigger_done;
struct completion init_device_done, reload_start_done, resume_done;
int board_id;
int led_state;
};
void smscore_set_board_id(struct smscore_device_t *core, int id)
{
core->board_id = id;
@ -384,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params,
init_completion(&dev->init_device_done);
init_completion(&dev->reload_start_done);
init_completion(&dev->resume_done);
init_completion(&dev->gpio_configuration_done);
init_completion(&dev->gpio_set_level_done);
init_completion(&dev->gpio_get_level_done);
init_completion(&dev->ir_init_done);
/* Buffer management */
init_waitqueue_head(&dev->buffer_mng_waitq);
/* alloc common buffer */
dev->common_buffer_size = params->buffer_size * params->num_buffers;
@ -439,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params,
}
EXPORT_SYMBOL_GPL(smscore_register_device);
static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
void *buffer, size_t size, struct completion *completion) {
int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
if (rc < 0) {
sms_info("sendrequest returned error %d", rc);
return rc;
}
return wait_for_completion_timeout(completion,
msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
0 : -ETIME;
}
/**
* Starts & enables IR operations
*
* @return 0 on success, < 0 on error.
*/
static int smscore_init_ir(struct smscore_device_t *coredev)
{
int ir_io;
int rc;
void *buffer;
coredev->ir.input_dev = NULL;
ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
if (ir_io) {/* only if IR port exist we use IR sub-module */
sms_info("IR loading");
rc = sms_ir_init(coredev);
if (rc != 0)
sms_err("Error initialization DTV IR sub-module");
else {
buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (buffer) {
struct SmsMsgData_ST2 *msg =
(struct SmsMsgData_ST2 *)
SMS_ALIGN_ADDRESS(buffer);
SMS_INIT_MSG(&msg->xMsgHeader,
MSG_SMS_START_IR_REQ,
sizeof(struct SmsMsgData_ST2));
msg->msgData[0] = coredev->ir.controller;
msg->msgData[1] = coredev->ir.timeout;
smsendian_handle_tx_message(
(struct SmsMsgHdr_ST2 *)msg);
rc = smscore_sendrequest_and_wait(coredev, msg,
msg->xMsgHeader. msgLength,
&coredev->ir_init_done);
kfree(buffer);
} else
sms_err
("Sending IR initialization message failed");
}
} else
sms_info("IR port has not been detected");
return 0;
}
/**
* sets initial device mode and notifies client hotplugs that device is ready
*
@ -459,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
kmutex_lock(&g_smscore_deviceslock);
rc = smscore_notify_callbacks(coredev, coredev->device, 1);
smscore_init_ir(coredev);
sms_info("device %p started, rc %d", coredev, rc);
@ -468,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev)
}
EXPORT_SYMBOL_GPL(smscore_start_device);
static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
void *buffer, size_t size,
struct completion *completion)
{
int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
if (rc < 0) {
sms_info("sendrequest returned error %d", rc);
return rc;
}
return wait_for_completion_timeout(completion,
msecs_to_jiffies(10000)) ?
0 : -ETIME;
}
static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
void *buffer, size_t size)
{
struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
struct SmsMsgHdr_ST *msg;
u32 mem_address = firmware->StartAddress;
u32 mem_address;
u8 *payload = firmware->Payload;
int rc = 0;
firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
firmware->Length = le32_to_cpu(firmware->Length);
mem_address = firmware->StartAddress;
sms_info("loading FW to addr 0x%x size %d",
mem_address, firmware->Length);
@ -657,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
kmutex_lock(&g_smscore_deviceslock);
/* Release input device (IR) resources */
sms_ir_exit(coredev);
smscore_notify_clients(coredev);
smscore_notify_callbacks(coredev, NULL, 0);
@ -664,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
* onresponse must no longer be called */
while (1) {
while ((cb = smscore_getbuffer(coredev))) {
while (!list_empty(&coredev->buffers)) {
cb = (struct smscore_buffer_t *) coredev->buffers.next;
list_del(&cb->entry);
kfree(cb);
num_buffers++;
}
@ -685,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
if (coredev->common_buffer)
dma_free_coherent(NULL, coredev->common_buffer_size,
coredev->common_buffer,
coredev->common_buffer_phys);
coredev->common_buffer, coredev->common_buffer_phys);
if (coredev->fw_buf != NULL)
kfree(coredev->fw_buf);
list_del(&coredev->entry);
kfree(coredev);
@ -746,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
/*BDA*/
{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
/*ISDBT*/
{"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
/*ISDBTBDA*/
{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
/*CMMB*/
@ -870,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
}
if (rc != 0)
if (rc < 0)
sms_err("return error code %d.", rc);
return rc;
}
@ -940,14 +978,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
*
*/
void smscore_onresponse(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb)
{
struct SmsMsgHdr_ST *phdr =
(struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
struct smscore_client_t *client =
smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
struct smscore_buffer_t *cb) {
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+ cb->offset);
struct smscore_client_t *client;
int rc = -EBUSY;
static unsigned long last_sample_time; /* = 0; */
static int data_total; /* = 0; */
unsigned long time_now = jiffies_to_msecs(jiffies);
@ -965,6 +1000,16 @@ void smscore_onresponse(struct smscore_device_t *coredev,
}
data_total += cb->size;
/* Do we need to re-route? */
if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
(phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
if (coredev->mode == DEVICE_MODE_DVBT_BDA)
phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
}
client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
/* If no client registered for type & id,
* check for control client where type is not registered */
if (client)
@ -1009,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev,
case MSG_SMS_SLEEP_RESUME_COMP_IND:
complete(&coredev->resume_done);
break;
case MSG_SMS_GPIO_CONFIG_EX_RES:
sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
complete(&coredev->gpio_configuration_done);
break;
case MSG_SMS_GPIO_SET_LEVEL_RES:
sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
complete(&coredev->gpio_set_level_done);
break;
case MSG_SMS_GPIO_GET_LEVEL_RES:
{
u32 *msgdata = (u32 *) phdr;
coredev->gpio_get_res = msgdata[1];
sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
coredev->gpio_get_res);
complete(&coredev->gpio_get_level_done);
break;
}
case MSG_SMS_START_IR_RES:
complete(&coredev->ir_init_done);
break;
case MSG_SMS_IR_SAMPLES_IND:
sms_ir_event(coredev,
(const char *)
((char *)phdr
+ sizeof(struct SmsMsgHdr_ST)),
(int)phdr->msgLength
- sizeof(struct SmsMsgHdr_ST));
break;
default:
break;
}
@ -1030,12 +1104,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
struct smscore_buffer_t *cb = NULL;
unsigned long flags;
DEFINE_WAIT(wait);
spin_lock_irqsave(&coredev->bufferslock, flags);
if (!list_empty(&coredev->buffers)) {
cb = (struct smscore_buffer_t *) coredev->buffers.next;
list_del(&cb->entry);
}
/* This function must return a valid buffer, since the buffer list is
* finite, we check that there is an available buffer, if not, we wait
* until such buffer become available.
*/
prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
if (list_empty(&coredev->buffers))
schedule();
finish_wait(&coredev->buffer_mng_waitq, &wait);
cb = (struct smscore_buffer_t *) coredev->buffers.next;
list_del(&cb->entry);
spin_unlock_irqrestore(&coredev->bufferslock, flags);
@ -1052,8 +1138,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
*
*/
void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb)
{
struct smscore_buffer_t *cb) {
wake_up_interruptible(&coredev->buffer_mng_waitq);
list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
}
EXPORT_SYMBOL_GPL(smscore_putbuffer);
@ -1210,8 +1296,9 @@ int smsclient_sendrequest(struct smscore_client_t *client,
EXPORT_SYMBOL_GPL(smsclient_sendrequest);
/* old GPIO managments implementation */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_gpio_config *pinconfig)
struct smscore_config_gpio *pinconfig)
{
struct {
struct SmsMsgHdr_ST hdr;
@ -1280,6 +1367,238 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
&msg, sizeof(msg));
}
/* new GPIO managment implementation */
static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
u32 *pGroupNum, u32 *pGroupCfg) {
*pGroupCfg = 1;
if (PinNum >= 0 && PinNum <= 1) {
*pTranslatedPinNum = 0;
*pGroupNum = 9;
*pGroupCfg = 2;
} else if (PinNum >= 2 && PinNum <= 6) {
*pTranslatedPinNum = 2;
*pGroupNum = 0;
*pGroupCfg = 2;
} else if (PinNum >= 7 && PinNum <= 11) {
*pTranslatedPinNum = 7;
*pGroupNum = 1;
} else if (PinNum >= 12 && PinNum <= 15) {
*pTranslatedPinNum = 12;
*pGroupNum = 2;
*pGroupCfg = 3;
} else if (PinNum == 16) {
*pTranslatedPinNum = 16;
*pGroupNum = 23;
} else if (PinNum >= 17 && PinNum <= 24) {
*pTranslatedPinNum = 17;
*pGroupNum = 3;
} else if (PinNum == 25) {
*pTranslatedPinNum = 25;
*pGroupNum = 6;
} else if (PinNum >= 26 && PinNum <= 28) {
*pTranslatedPinNum = 26;
*pGroupNum = 4;
} else if (PinNum == 29) {
*pTranslatedPinNum = 29;
*pGroupNum = 5;
*pGroupCfg = 2;
} else if (PinNum == 30) {
*pTranslatedPinNum = 30;
*pGroupNum = 8;
} else if (PinNum == 31) {
*pTranslatedPinNum = 31;
*pGroupNum = 17;
} else
return -1;
*pGroupCfg <<= 24;
return 0;
}
int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
struct smscore_gpio_config *pGpioConfig) {
u32 totalLen;
u32 TranslatedPinNum;
u32 GroupNum;
u32 ElectricChar;
u32 groupCfg;
void *buffer;
int rc;
struct SetGpioMsg {
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[6];
} *pMsg;
if (PinNum > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
if (pGpioConfig == NULL)
return -EINVAL;
totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
pMsg->xMsgHeader.msgDstId = HIF_TASK;
pMsg->xMsgHeader.msgFlags = 0;
pMsg->xMsgHeader.msgLength = (u16) totalLen;
pMsg->msgData[0] = PinNum;
if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
&groupCfg) != 0)
return -EINVAL;
pMsg->msgData[1] = TranslatedPinNum;
pMsg->msgData[2] = GroupNum;
ElectricChar = (pGpioConfig->PullUpDown)
| (pGpioConfig->InputCharacteristics << 2)
| (pGpioConfig->OutputSlewRate << 3)
| (pGpioConfig->OutputDriving << 4);
pMsg->msgData[3] = ElectricChar;
pMsg->msgData[4] = pGpioConfig->Direction;
pMsg->msgData[5] = groupCfg;
} else {
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
pMsg->msgData[1] = pGpioConfig->PullUpDown;
pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
pMsg->msgData[3] = pGpioConfig->OutputDriving;
pMsg->msgData[4] = pGpioConfig->Direction;
pMsg->msgData[5] = 0;
}
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
&coredev->gpio_configuration_done);
if (rc != 0) {
if (rc == -ETIME)
sms_err("smscore_gpio_configure timeout");
else
sms_err("smscore_gpio_configure error");
}
kfree(buffer);
return rc;
}
int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
u8 NewLevel) {
u32 totalLen;
int rc;
void *buffer;
struct SetGpioMsg {
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[3]; /* keep it 3 ! */
} *pMsg;
if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
(PinNum > MAX_GPIO_PIN_NUMBER))
return -EINVAL;
totalLen = sizeof(struct SmsMsgHdr_ST) +
(3 * sizeof(u32)); /* keep it 3 ! */
buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
pMsg->xMsgHeader.msgDstId = HIF_TASK;
pMsg->xMsgHeader.msgFlags = 0;
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
pMsg->xMsgHeader.msgLength = (u16) totalLen;
pMsg->msgData[0] = PinNum;
pMsg->msgData[1] = NewLevel;
/* Send message to SMS */
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
&coredev->gpio_set_level_done);
if (rc != 0) {
if (rc == -ETIME)
sms_err("smscore_gpio_set_level timeout");
else
sms_err("smscore_gpio_set_level error");
}
kfree(buffer);
return rc;
}
int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
u8 *level) {
u32 totalLen;
int rc;
void *buffer;
struct SetGpioMsg {
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[2];
} *pMsg;
if (PinNum > MAX_GPIO_PIN_NUMBER)
return -EINVAL;
totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
pMsg->xMsgHeader.msgDstId = HIF_TASK;
pMsg->xMsgHeader.msgFlags = 0;
pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
pMsg->xMsgHeader.msgLength = (u16) totalLen;
pMsg->msgData[0] = PinNum;
pMsg->msgData[1] = 0;
/* Send message to SMS */
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
&coredev->gpio_get_level_done);
if (rc != 0) {
if (rc == -ETIME)
sms_err("smscore_gpio_get_level timeout");
else
sms_err("smscore_gpio_get_level error");
}
kfree(buffer);
/* Its a race between other gpio_get_level() and the copy of the single
* global 'coredev->gpio_get_res' to the function's variable 'level'
*/
*level = coredev->gpio_get_res;
return rc;
}
static int __init smscore_module_init(void)
{
int rc = 0;
@ -1291,24 +1610,11 @@ static int __init smscore_module_init(void)
INIT_LIST_HEAD(&g_smscore_registry);
kmutex_init(&g_smscore_registrylock);
return rc;
sms_debug("rc %d", rc);
return rc;
}
static void __exit smscore_module_exit(void)
{
kmutex_lock(&g_smscore_deviceslock);
while (!list_empty(&g_smscore_notifyees)) {
struct smscore_device_notifyee_t *notifyee =

View file

@ -1,26 +1,26 @@
/*
* Driver for the Siano SMS1xxx USB dongle
*
* author: Anatoly Greenblat
*
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
*
* 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 __smscoreapi_h__
#define __smscoreapi_h__
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#ifndef __SMS_CORE_API_H__
#define __SMS_CORE_API_H__
#include <linux/version.h>
#include <linux/device.h>
@ -28,14 +28,13 @@
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/types.h>
#include <asm/page.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include <asm/page.h>
#include "smsir.h"
#define kmutex_init(_p_) mutex_init(_p_)
#define kmutex_lock(_p_) mutex_lock(_p_)
@ -46,13 +45,14 @@
#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#define SMS_ALLOC_ALIGNMENT 128
#define SMS_DMA_ALIGNMENT 16
#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000)
#define SMS_ALLOC_ALIGNMENT 128
#define SMS_DMA_ALIGNMENT 16
#define SMS_ALIGN_ADDRESS(addr) \
((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
#define SMS_DEVICE_FAMILY2 1
#define SMS_ROM_NO_RESPONSE 2
#define SMS_DEVICE_FAMILY2 1
#define SMS_ROM_NO_RESPONSE 2
#define SMS_DEVICE_NOT_READY 0x8000000
enum sms_device_type_st {
@ -83,13 +83,13 @@ typedef void (*onremove_t)(void *context);
struct smscore_buffer_t {
/* public members, once passed to clients can be changed freely */
struct list_head entry;
int size;
int offset;
int size;
int offset;
/* private members, read-only for clients */
void *p;
dma_addr_t phys;
unsigned long offset_in_common;
void *p;
dma_addr_t phys;
unsigned long offset_in_common;
};
struct smsdevice_params_t {
@ -116,10 +116,63 @@ struct smsclient_params_t {
int data_type;
onresponse_t onresponse_handler;
onremove_t onremove_handler;
void *context;
};
struct smscore_device_t {
struct list_head entry;
struct list_head clients;
struct list_head subclients;
spinlock_t clientslock;
struct list_head buffers;
spinlock_t bufferslock;
int num_buffers;
void *common_buffer;
int common_buffer_size;
dma_addr_t common_buffer_phys;
void *context;
struct device *device;
char devpath[32];
unsigned long device_flags;
setmode_t setmode_handler;
detectmode_t detectmode_handler;
sendrequest_t sendrequest_handler;
preload_t preload_handler;
postload_t postload_handler;
int mode, modes_supported;
/* host <--> device messages */
struct completion version_ex_done, data_download_done, trigger_done;
struct completion init_device_done, reload_start_done, resume_done;
struct completion gpio_configuration_done, gpio_set_level_done;
struct completion gpio_get_level_done, ir_init_done;
/* Buffer management */
wait_queue_head_t buffer_mng_waitq;
/* GPIO */
int gpio_get_res;
/* Target hardware board */
int board_id;
/* Firmware */
u8 *fw_buf;
u32 fw_buf_size;
/* Infrared (IR) */
struct ir_t ir;
int led_state;
};
/* GPIO definitions for antenna frequency domain control (SMS8021) */
#define SMS_ANTENNA_GPIO_0 1
#define SMS_ANTENNA_GPIO_1 0
@ -154,18 +207,15 @@ struct smsclient_params_t {
#define MSG_SMS_INIT_DEVICE_RES 579
#define MSG_SMS_ADD_PID_FILTER_REQ 601
#define MSG_SMS_ADD_PID_FILTER_RES 602
#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
#define MSG_SMS_REMOVE_PID_FILTER_RES 604
#define MSG_SMS_DAB_CHANNEL 607
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
#define MSG_SMS_GET_STATISTICS_REQ 615
#define MSG_SMS_GET_STATISTICS_RES 616
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
#define MSG_SMS_GET_STATISTICS_EX_REQ 653
#define MSG_SMS_GET_STATISTICS_EX_RES 654
#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
#define MSG_SMS_REMOVE_PID_FILTER_RES 604
#define MSG_SMS_DAB_CHANNEL 607
#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
#define MSG_SMS_HO_PER_SLICES_IND 630
#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
#define MSG_SMS_DATA_DOWNLOAD_REQ 660
#define MSG_SMS_DATA_DOWNLOAD_RES 661
#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
@ -190,14 +240,31 @@ struct smsclient_params_t {
#define MSG_SMS_GPIO_CONFIG_EX_RES 713
#define MSG_SMS_ISDBT_TUNE_REQ 776
#define MSG_SMS_ISDBT_TUNE_RES 777
#define MSG_SMS_TRANSMISSION_IND 782
#define MSG_SMS_START_IR_REQ 800
#define MSG_SMS_START_IR_RES 801
#define MSG_SMS_IR_SAMPLES_IND 802
#define MSG_SMS_SIGNAL_DETECTED_IND 827
#define MSG_SMS_NO_SIGNAL_IND 828
#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
(ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
(ptr)->msgLength = len; (ptr)->msgFlags = 0; \
} while (0)
#define SMS_INIT_MSG(ptr, type, len) \
SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
enum SMS_DVB3_EVENTS {
DVB3_EVENT_INIT = 0,
DVB3_EVENT_SLEEP,
DVB3_EVENT_HOTPLUG,
DVB3_EVENT_FE_LOCK,
DVB3_EVENT_FE_UNLOCK,
DVB3_EVENT_UNC_OK,
DVB3_EVENT_UNC_ERR
};
enum SMS_DEVICE_MODE {
DEVICE_MODE_NONE = -1,
DEVICE_MODE_DVBT = 0,
@ -221,8 +288,13 @@ struct SmsMsgHdr_ST {
};
struct SmsMsgData_ST {
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[1];
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[1];
};
struct SmsMsgData_ST2 {
struct SmsMsgHdr_ST xMsgHeader;
u32 msgData[2];
};
struct SmsDataDownload_ST {
@ -238,11 +310,12 @@ struct SmsVersionRes_ST {
u8 Step; /* 0 - Step A */
u8 MetalFix; /* 0 - Metal 0 */
u8 FirmwareId; /* 0xFF <20> ROM, otherwise the
* value indicated by
* SMSHOSTLIB_DEVICE_MODES_E */
u8 SupportedProtocols; /* Bitwise OR combination of
/* FirmwareId 0xFF if ROM, otherwise the
* value indicated by SMSHOSTLIB_DEVICE_MODES_E */
u8 FirmwareId;
/* SupportedProtocols Bitwise OR combination of
* supported protocols */
u8 SupportedProtocols;
u8 VersionMajor;
u8 VersionMinor;
@ -264,86 +337,219 @@ struct SmsFirmware_ST {
u8 Payload[1];
};
struct SMSHOSTLIB_STATISTICS_ST {
u32 Reserved; /* Reserved */
/* Statistics information returned as response for
* SmsHostApiGetStatistics_Req */
struct SMSHOSTLIB_STATISTICS_S {
u32 Reserved; /* Reserved */
/* Common parameters */
u32 IsRfLocked; /* 0 - not locked, 1 - locked */
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
u32 IsRfLocked; /* 0 - not locked, 1 - locked */
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
/* Reception quality */
s32 SNR; /* dB */
u32 BER; /* Post Viterbi BER [1E-5] */
u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
* valid only for DVB-T/H */
u32 MFER; /* DVB-H frame error rate in percentage,
* 0xFFFFFFFF indicate N/A, valid only for DVB-H */
s32 RSSI; /* dBm */
s32 InBandPwr; /* In band power in dBM */
s32 CarrierOffset; /* Carrier Offset in bin/1024 */
s32 SNR; /* dB */
u32 BER; /* Post Viterbi BER [1E-5] */
u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
u32 TS_PER; /* Transport stream PER,
0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
u32 MFER; /* DVB-H frame error rate in percentage,
0xFFFFFFFF indicate N/A, valid only for DVB-H */
s32 RSSI; /* dBm */
s32 InBandPwr; /* In band power in dBM */
s32 CarrierOffset; /* Carrier Offset in bin/1024 */
/* Transmission parameters, valid only for DVB-T/H */
u32 Frequency; /* Frequency in Hz */
u32 Bandwidth; /* Bandwidth in MHz */
u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
* for DVB-T/H FFT mode carriers in Kilos */
u32 ModemState; /* from SMS_DvbModemState_ET */
u32 GuardInterval; /* Guard Interval, 1 divided by value */
u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
u32 Constellation; /* Constellation from SMS_Constellation_ET */
/* Transmission parameters */
u32 Frequency; /* Frequency in Hz */
u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */
u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
for DVB-T/H FFT mode carriers in Kilos */
u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
valid only for DVB-T/H */
u32 GuardInterval; /* Guard Interval from
SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */
u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
valid only for DVB-T/H */
u32 LPCodeRate; /* Low Priority Code Rate from
SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
valid only for DVB-T/H */
u32 Constellation; /* Constellation from
SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
/* Burst parameters, valid only for DVB-H */
u32 BurstSize; /* Current burst size in bytes */
u32 BurstDuration; /* Current burst duration in mSec */
u32 BurstCycleTime; /* Current burst cycle time in mSec */
u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
* as calculated by demodulator */
u32 NumOfRows; /* Number of rows in MPE table */
u32 NumOfPaddCols; /* Number of padding columns in MPE table */
u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
/* Burst parameters */
u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
u32 TotalTSPackets; /* Total number of transport-stream packets */
u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
* errors after MPE RS decoding */
u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
* after MPE RS decoding */
u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
* by MPE RS decoding */
u32 BurstSize; /* Current burst size in bytes,
valid only for DVB-H */
u32 BurstDuration; /* Current burst duration in mSec,
valid only for DVB-H */
u32 BurstCycleTime; /* Current burst cycle time in mSec,
valid only for DVB-H */
u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
as calculated by demodulator, valid only for DVB-H */
u32 NumOfRows; /* Number of rows in MPE table,
valid only for DVB-H */
u32 NumOfPaddCols; /* Number of padding columns in MPE table,
valid only for DVB-H */
u32 NumOfPunctCols; /* Number of puncturing columns in MPE table,
valid only for DVB-H */
u32 ErrorTSPackets; /* Number of erroneous
transport-stream packets */
u32 TotalTSPackets; /* Total number of transport-stream packets */
u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
errors after MPE RS decoding */
u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
after MPE RS decoding */
u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
corrected by MPE RS decoding */
/* Common params */
u32 BERErrorCount; /* Number of errornous SYNC bits. */
u32 BERBitCount; /* Total number of SYNC bits. */
u32 BERErrorCount; /* Number of errornous SYNC bits. */
u32 BERBitCount; /* Total number of SYNC bits. */
/* Interface information */
u32 SmsToHostTxErrors; /* Total number of transmission errors. */
u32 SmsToHostTxErrors; /* Total number of transmission errors. */
/* DAB/T-DMB */
u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
/* DVB-H TPS parameters */
u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
* if set to 0xFFFFFFFF cell_id not yet recovered */
u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
if set to 0xFFFFFFFF cell_id not yet recovered */
u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
u32 NumMPEReceived; /* DVB-H, Num MPE section received */
u32 ReservedFields[10]; /* Reserved */
};
struct SmsMsgStatisticsInfo_ST {
u32 RequestResult;
struct PID_STATISTICS_DATA_S {
struct PID_BURST_S {
u32 size;
u32 padding_cols;
u32 punct_cols;
u32 duration;
u32 cycle;
u32 calc_cycle;
} burst;
struct SMSHOSTLIB_STATISTICS_ST Stat;
u32 tot_tbl_cnt;
u32 invalid_tbl_cnt;
u32 tot_cor_tbl;
};
/* Split the calc of the SNR in DAB */
u32 Signal; /* dB */
u32 Noise; /* dB */
struct PID_DATA_S {
u32 pid;
u32 num_rows;
struct PID_STATISTICS_DATA_S pid_statistics;
};
#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
if (_stat.TransmissionMode == 0) \
_stat.TransmissionMode = 2; \
else if (_stat.TransmissionMode == 1) \
_stat.TransmissionMode = 8; \
else \
_stat.TransmissionMode = 4;
struct TRANSMISSION_STATISTICS_S {
u32 Frequency; /* Frequency in Hz */
u32 Bandwidth; /* Bandwidth in MHz */
u32 TransmissionMode; /* FFT mode carriers in Kilos */
u32 GuardInterval; /* Guard Interval from
SMSHOSTLIB_GUARD_INTERVALS_ET */
u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
u32 LPCodeRate; /* Low Priority Code Rate from
SMSHOSTLIB_CODE_RATE_ET */
u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
u32 Constellation; /* Constellation from
SMSHOSTLIB_CONSTELLATION_ET */
/* DVB-H TPS parameters */
u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
if set to 0xFFFFFFFF cell_id not yet recovered */
u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
Time Slicing indicator, bit 0 - MPE-FEC indicator */
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
};
struct RECEPTION_STATISTICS_S {
u32 IsRfLocked; /* 0 - not locked, 1 - locked */
u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
s32 SNR; /* dB */
u32 BER; /* Post Viterbi BER [1E-5] */
u32 BERErrorCount; /* Number of erronous SYNC bits. */
u32 BERBitCount; /* Total number of SYNC bits. */
u32 TS_PER; /* Transport stream PER,
0xFFFFFFFF indicate N/A */
u32 MFER; /* DVB-H frame error rate in percentage,
0xFFFFFFFF indicate N/A, valid only for DVB-H */
s32 RSSI; /* dBm */
s32 InBandPwr; /* In band power in dBM */
s32 CarrierOffset; /* Carrier Offset in bin/1024 */
u32 ErrorTSPackets; /* Number of erroneous
transport-stream packets */
u32 TotalTSPackets; /* Total number of transport-stream packets */
s32 MRC_SNR; /* dB */
s32 MRC_RSSI; /* dBm */
s32 MRC_InBandPwr; /* In band power in dBM */
};
struct smscore_gpio_config {
/* Statistics information returned as response for
* SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
struct SMSHOSTLIB_STATISTICS_DVB_S {
/* Reception */
struct RECEPTION_STATISTICS_S ReceptionData;
/* Transmission parameters */
struct TRANSMISSION_STATISTICS_S TransmissionData;
/* Burst parameters, valid only for DVB-H */
#define SRVM_MAX_PID_FILTERS 8
struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
};
struct SRVM_SIGNAL_STATUS_S {
u32 result;
u32 snr;
u32 tsPackets;
u32 etsPackets;
u32 constellation;
u32 hpCode;
u32 tpsSrvIndLP;
u32 tpsSrvIndHP;
u32 cellId;
u32 reason;
s32 inBandPower;
u32 requestId;
};
struct SMSHOSTLIB_I2C_REQ_ST {
u32 DeviceAddress; /* I2c device address */
u32 WriteCount; /* number of bytes to write */
u32 ReadCount; /* number of bytes to read */
u8 Data[1];
};
struct SMSHOSTLIB_I2C_RES_ST {
u32 Status; /* non-zero value in case of failure */
u32 ReadCount; /* number of bytes read */
u8 Data[1];
};
struct smscore_config_gpio {
#define SMS_GPIO_DIRECTION_INPUT 0
#define SMS_GPIO_DIRECTION_OUTPUT 1
u8 direction;
@ -369,6 +575,47 @@ struct smscore_gpio_config {
u8 outputdriving;
};
struct smscore_gpio_config {
#define SMS_GPIO_DIRECTION_INPUT 0
#define SMS_GPIO_DIRECTION_OUTPUT 1
u8 Direction;
#define SMS_GPIO_PULL_UP_DOWN_NONE 0
#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2
#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3
u8 PullUpDown;
#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0
#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
u8 InputCharacteristics;
#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */
#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */
#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */
#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */
#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */
#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */
u8 OutputSlewRate;
#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */
#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */
#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */
#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */
#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */
#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */
u8 OutputDriving;
};
extern void smscore_registry_setmode(char *devpath, int mode);
extern int smscore_registry_getmode(char *devpath);
@ -410,10 +657,19 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
extern void smscore_putbuffer(struct smscore_device_t *coredev,
struct smscore_buffer_t *cb);
/* old GPIO managment */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_gpio_config *pinconfig);
struct smscore_config_gpio *pinconfig);
int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
/* new GPIO managment */
extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
struct smscore_gpio_config *pGpioConfig);
extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
u8 NewLevel);
extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
u8 *level);
void smscore_set_board_id(struct smscore_device_t *core, int id);
int smscore_get_board_id(struct smscore_device_t *core);
@ -442,4 +698,4 @@ int smscore_led_state(struct smscore_device_t *core, int led);
dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
#endif /* __smscoreapi_h__ */
#endif /* __SMS_CORE_API_H__ */

View file

@ -1,28 +1,34 @@
/*
* Driver for the Siano SMS1xxx USB dongle
*
* Author: Uri Shkolni
*
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
*
* 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.
*/
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2008, Uri Shkolnik
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "smscoreapi.h"
#include "smsendian.h"
#include "sms-cards.h"
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@ -39,12 +45,15 @@ struct smsdvb_client_t {
struct dvb_frontend frontend;
fe_status_t fe_status;
int fe_ber, fe_snr, fe_unc, fe_signal_strength;
struct completion tune_done, stat_done;
struct completion tune_done;
/* todo: save freq/band instead whole struct */
struct dvb_frontend_parameters fe_params;
struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
int event_fe_state;
int event_unc_state;
};
static struct list_head g_smsdvb_clients;
@ -54,11 +63,69 @@ static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
/* Events that may come from DVB v3 adapter */
static void sms_board_dvb3_event(struct smsdvb_client_t *client,
enum SMS_DVB3_EVENTS event) {
struct smscore_device_t *coredev = client->coredev;
switch (event) {
case DVB3_EVENT_INIT:
sms_debug("DVB3_EVENT_INIT");
sms_board_event(coredev, BOARD_EVENT_BIND);
break;
case DVB3_EVENT_SLEEP:
sms_debug("DVB3_EVENT_SLEEP");
sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
break;
case DVB3_EVENT_HOTPLUG:
sms_debug("DVB3_EVENT_HOTPLUG");
sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
break;
case DVB3_EVENT_FE_LOCK:
if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
client->event_fe_state = DVB3_EVENT_FE_LOCK;
sms_debug("DVB3_EVENT_FE_LOCK");
sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
}
break;
case DVB3_EVENT_FE_UNLOCK:
if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
sms_debug("DVB3_EVENT_FE_UNLOCK");
sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
}
break;
case DVB3_EVENT_UNC_OK:
if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
client->event_unc_state = DVB3_EVENT_UNC_OK;
sms_debug("DVB3_EVENT_UNC_OK");
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
}
break;
case DVB3_EVENT_UNC_ERR:
if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
client->event_unc_state = DVB3_EVENT_UNC_ERR;
sms_debug("DVB3_EVENT_UNC_ERR");
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
}
break;
default:
sms_err("Unknown dvb3 api event");
break;
}
}
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
{
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
struct SmsMsgHdr_ST *phdr =
(struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+ cb->offset);
u32 *pMsgData = (u32 *) phdr + 1;
/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
bool is_status_update = false;
smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
switch (phdr->msgType) {
case MSG_SMS_DVBT_BDA_DATA:
@ -70,43 +137,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
complete(&client->tune_done);
break;
case MSG_SMS_GET_STATISTICS_RES:
{
struct SmsMsgStatisticsInfo_ST *p =
(struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
case MSG_SMS_SIGNAL_DETECTED_IND:
sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
is_status_update = true;
break;
if (p->Stat.IsDemodLocked) {
client->fe_status = FE_HAS_SIGNAL |
FE_HAS_CARRIER |
FE_HAS_VITERBI |
FE_HAS_SYNC |
FE_HAS_LOCK;
case MSG_SMS_NO_SIGNAL_IND:
sms_info("MSG_SMS_NO_SIGNAL_IND");
client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
is_status_update = true;
break;
client->fe_snr = p->Stat.SNR;
client->fe_ber = p->Stat.BER;
client->fe_unc = p->Stat.BERErrorCount;
case MSG_SMS_TRANSMISSION_IND: {
sms_info("MSG_SMS_TRANSMISSION_IND");
if (p->Stat.InBandPwr < -95)
client->fe_signal_strength = 0;
else if (p->Stat.InBandPwr > -29)
client->fe_signal_strength = 100;
else
client->fe_signal_strength =
(p->Stat.InBandPwr + 95) * 3 / 2;
pMsgData++;
memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
sizeof(struct TRANSMISSION_STATISTICS_S));
/* Mo need to correct guard interval
* (as opposed to old statistics message).
*/
CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
CORRECT_STAT_TRANSMISSON_MODE(
client->sms_stat_dvb.TransmissionData);
is_status_update = true;
break;
}
case MSG_SMS_HO_PER_SLICES_IND: {
struct RECEPTION_STATISTICS_S *pReceptionData =
&client->sms_stat_dvb.ReceptionData;
struct SRVM_SIGNAL_STATUS_S SignalStatusData;
/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
pMsgData++;
SignalStatusData.result = pMsgData[0];
SignalStatusData.snr = pMsgData[1];
SignalStatusData.inBandPower = (s32) pMsgData[2];
SignalStatusData.tsPackets = pMsgData[3];
SignalStatusData.etsPackets = pMsgData[4];
SignalStatusData.constellation = pMsgData[5];
SignalStatusData.hpCode = pMsgData[6];
SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
SignalStatusData.reason = pMsgData[10];
SignalStatusData.requestId = pMsgData[11];
pReceptionData->IsRfLocked = pMsgData[16];
pReceptionData->IsDemodLocked = pMsgData[17];
pReceptionData->ModemState = pMsgData[12];
pReceptionData->SNR = pMsgData[1];
pReceptionData->BER = pMsgData[13];
pReceptionData->RSSI = pMsgData[14];
CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
pReceptionData->InBandPwr = (s32) pMsgData[2];
pReceptionData->CarrierOffset = (s32) pMsgData[15];
pReceptionData->TotalTSPackets = pMsgData[3];
pReceptionData->ErrorTSPackets = pMsgData[4];
/* TS PER */
if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
> 0) {
pReceptionData->TS_PER = (SignalStatusData.etsPackets
* 100) / (SignalStatusData.tsPackets
+ SignalStatusData.etsPackets);
} else {
client->fe_status = 0;
client->fe_snr =
client->fe_ber =
client->fe_unc =
client->fe_signal_strength = 0;
pReceptionData->TS_PER = 0;
}
complete(&client->stat_done);
break;
} }
pReceptionData->BERBitCount = pMsgData[18];
pReceptionData->BERErrorCount = pMsgData[19];
pReceptionData->MRC_SNR = pMsgData[20];
pReceptionData->MRC_InBandPwr = pMsgData[21];
pReceptionData->MRC_RSSI = pMsgData[22];
is_status_update = true;
break;
}
}
smscore_putbuffer(client->coredev, cb);
if (is_status_update) {
if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
== 0)
sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
else
sms_board_dvb3_event(client,
DVB3_EVENT_UNC_ERR);
} else {
/*client->fe_status =
(phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
0 : FE_HAS_SIGNAL;*/
client->fe_status = 0;
sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
}
}
return 0;
}
@ -149,6 +283,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
PidMsg.msgData[0] = feed->pid;
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
return smsclient_sendrequest(client->smsclient,
&PidMsg, sizeof(PidMsg));
}
@ -169,6 +304,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
PidMsg.msgData[0] = feed->pid;
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
return smsclient_sendrequest(client->smsclient,
&PidMsg, sizeof(PidMsg));
}
@ -177,7 +313,10 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
void *buffer, size_t size,
struct completion *completion)
{
int rc = smsclient_sendrequest(client->smsclient, buffer, size);
int rc;
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
rc = smsclient_sendrequest(client->smsclient, buffer, size);
if (rc < 0)
return rc;
@ -186,83 +325,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
0 : -ETIME;
}
static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
{
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
DVBT_BDA_CONTROL_MSG_ID,
HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
&client->stat_done);
if (ret < 0)
return ret;
if (client->fe_status & FE_HAS_LOCK)
sms_board_led_feedback(client->coredev,
(client->fe_unc == 0) ?
SMS_LED_HI : SMS_LED_LO);
else
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
return ret;
}
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
if (!rc)
*stat = client->fe_status;
*stat = client->fe_status;
return rc;
return 0;
}
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
if (!rc)
*ber = client->fe_ber;
*ber = client->sms_stat_dvb.ReceptionData.BER;
return rc;
return 0;
}
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
if (!rc)
*strength = client->fe_signal_strength;
if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
*strength = 0;
else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
*strength = 100;
else
*strength =
(client->sms_stat_dvb.ReceptionData.InBandPwr
+ 95) * 3 / 2;
return rc;
return 0;
}
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
if (!rc)
*snr = client->fe_snr;
*snr = client->sms_stat_dvb.ReceptionData.SNR;
return rc;
return 0;
}
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
int rc = smsdvb_send_statistics_request(client);
struct smsdvb_client_t *client;
client = container_of(fe, struct smsdvb_client_t, frontend);
if (!rc)
*ucblocks = client->fe_unc;
*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
return rc;
return 0;
}
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@ -286,12 +403,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
struct SmsMsgHdr_ST Msg;
u32 Data[3];
} Msg;
int ret;
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
Msg.Msg.msgDstId = HIF_TASK;
Msg.Msg.msgFlags = 0;
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
client->fe_status = FE_HAS_SIGNAL;
client->event_fe_state = -1;
client->event_unc_state = -1;
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
Msg.Msg.msgDstId = HIF_TASK;
Msg.Msg.msgFlags = 0;
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Msg.Msg.msgLength = sizeof(Msg);
Msg.Data[0] = fep->frequency;
Msg.Data[2] = 12000000;
@ -307,24 +427,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
default: return -EINVAL;
}
/* Disable LNA, if any. An error is returned if no LNA is present */
ret = sms_board_lna_control(client->coredev, 0);
if (ret == 0) {
fe_status_t status;
/* tune with LNA off at first */
ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
&client->tune_done);
smsdvb_read_status(fe, &status);
if (status & FE_HAS_LOCK)
return ret;
/* previous tune didnt lock - enable LNA and tune again */
sms_board_lna_control(client->coredev, 1);
}
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
&client->tune_done);
}
@ -349,8 +451,7 @@ static int smsdvb_init(struct dvb_frontend *fe)
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
sms_board_power(client->coredev, 1);
sms_board_dvb3_event(client, DVB3_EVENT_INIT);
return 0;
}
@ -359,8 +460,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe)
struct smsdvb_client_t *client =
container_of(fe, struct smsdvb_client_t, frontend);
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
sms_board_power(client->coredev, 0);
sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
return 0;
}
@ -485,7 +585,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
client->coredev = coredev;
init_completion(&client->tune_done);
init_completion(&client->stat_done);
kmutex_lock(&g_smsdvb_clientslock);
@ -493,8 +592,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
kmutex_unlock(&g_smsdvb_clientslock);
sms_info("success");
client->event_fe_state = -1;
client->event_unc_state = -1;
sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
sms_info("success");
sms_board_setup(coredev);
return 0;
@ -547,5 +649,5 @@ module_init(smsdvb_module_init);
module_exit(smsdvb_module_exit);
MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,102 @@
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#include <asm/byteorder.h>
#include "smsendian.h"
#include "smscoreapi.h"
void smsendian_handle_tx_message(void *buffer)
{
#ifdef __BIG_ENDIAN
struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
int i;
int msgWords;
switch (msg->xMsgHeader.msgType) {
case MSG_SMS_DATA_DOWNLOAD_REQ:
{
msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
break;
}
default:
msgWords = (msg->xMsgHeader.msgLength -
sizeof(struct SmsMsgHdr_ST))/4;
for (i = 0; i < msgWords; i++)
msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
break;
}
#endif /* __BIG_ENDIAN */
}
EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
void smsendian_handle_rx_message(void *buffer)
{
#ifdef __BIG_ENDIAN
struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
int i;
int msgWords;
switch (msg->xMsgHeader.msgType) {
case MSG_SMS_GET_VERSION_EX_RES:
{
struct SmsVersionRes_ST *ver =
(struct SmsVersionRes_ST *) msg;
ver->ChipModel = le16_to_cpu(ver->ChipModel);
break;
}
case MSG_SMS_DVBT_BDA_DATA:
case MSG_SMS_DAB_CHANNEL:
case MSG_SMS_DATA_MSG:
{
break;
}
default:
{
msgWords = (msg->xMsgHeader.msgLength -
sizeof(struct SmsMsgHdr_ST))/4;
for (i = 0; i < msgWords; i++)
msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
break;
}
}
#endif /* __BIG_ENDIAN */
}
EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
void smsendian_handle_message_header(void *msg)
{
#ifdef __BIG_ENDIAN
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
phdr->msgType = le16_to_cpu(phdr->msgType);
phdr->msgLength = le16_to_cpu(phdr->msgLength);
phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
#endif /* __BIG_ENDIAN */
}
EXPORT_SYMBOL_GPL(smsendian_handle_message_header);

View file

@ -0,0 +1,32 @@
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#ifndef __SMS_ENDIAN_H__
#define __SMS_ENDIAN_H__
#include <asm/byteorder.h>
extern void smsendian_handle_tx_message(void *buffer);
extern void smsendian_handle_rx_message(void *buffer);
extern void smsendian_handle_message_header(void *msg);
#endif /* __SMS_ENDIAN_H__ */

View file

@ -0,0 +1,301 @@
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#include <linux/types.h>
#include <linux/input.h>
#include "smscoreapi.h"
#include "smsir.h"
#include "sms-cards.h"
/* In order to add new IR remote control -
* 1) Add it to the <enum ir_kb_type> @ smsir,h,
* 2) Add its map to keyboard_layout_maps below
* 3) Set your board (sms-cards sub-module) to use it
*/
static struct keyboard_layout_map_t keyboard_layout_maps[] = {
[SMS_IR_KB_DEFAULT_TV] = {
.ir_protocol = IR_RC5,
.rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
.keyboard_layout_map = {
KEY_0, KEY_1, KEY_2,
KEY_3, KEY_4, KEY_5,
KEY_6, KEY_7, KEY_8,
KEY_9, 0, 0, KEY_POWER,
KEY_MUTE, 0, 0,
KEY_VOLUMEUP, KEY_VOLUMEDOWN,
KEY_BRIGHTNESSUP,
KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
KEY_CHANNELDOWN,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}
},
[SMS_IR_KB_HCW_SILVER] = {
.ir_protocol = IR_RC5,
.rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
.keyboard_layout_map = {
KEY_0, KEY_1, KEY_2,
KEY_3, KEY_4, KEY_5,
KEY_6, KEY_7, KEY_8,
KEY_9, KEY_TEXT, KEY_RED,
KEY_RADIO, KEY_MENU,
KEY_SUBTITLE,
KEY_MUTE, KEY_VOLUMEUP,
KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
KEY_UP, KEY_DOWN, KEY_LEFT,
KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
KEY_MHP, KEY_EPG, KEY_TV,
0, KEY_NEXTSONG, KEY_EXIT,
KEY_CHANNELUP, KEY_CHANNELDOWN,
KEY_CHANNEL, 0,
KEY_PREVIOUSSONG, KEY_ENTER,
KEY_SLEEP, 0, 0, KEY_BLUE,
0, 0, 0, 0, KEY_GREEN, 0,
KEY_PAUSE, 0, KEY_REWIND,
0, KEY_FASTFORWARD, KEY_PLAY,
KEY_STOP, KEY_RECORD,
KEY_YELLOW, 0, 0, KEY_SELECT,
KEY_ZOOM, KEY_POWER, 0, 0
}
},
{ } /* Terminating entry */
};
u32 ir_pos;
u32 ir_word;
u32 ir_toggle;
#define RC5_PUSH_BIT(dst, bit, pos) \
{ dst <<= 1; dst |= bit; pos++; }
static void sms_ir_rc5_event(struct smscore_device_t *coredev,
u32 toggle, u32 addr, u32 cmd)
{
bool toggle_changed;
u16 keycode;
sms_log("IR RC5 word: address %d, command %d, toggle %d",
addr, cmd, toggle);
toggle_changed = ir_toggle != toggle;
/* keep toggle */
ir_toggle = toggle;
if (addr !=
keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
return; /* Check for valid address */
keycode =
keyboard_layout_maps
[coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
if (!toggle_changed &&
(keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
return; /* accept only repeated volume, reject other keys */
sms_log("kernel input keycode (from ir) %d", keycode);
input_report_key(coredev->ir.input_dev, keycode, 1);
input_sync(coredev->ir.input_dev);
}
/* decode raw bit pattern to RC5 code */
/* taken from ir-functions.c */
static u32 ir_rc5_decode(unsigned int code)
{
/* unsigned int org_code = code;*/
unsigned int pair;
unsigned int rc5 = 0;
int i;
for (i = 0; i < 14; ++i) {
pair = code & 0x3;
code >>= 2;
rc5 <<= 1;
switch (pair) {
case 0:
case 2:
break;
case 1:
rc5 |= 1;
break;
case 3:
/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
sms_log("bad code");
return 0;
}
}
/*
dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
toggle=%x, address=%x, "
"instr=%x\n", rc5, org_code, RC5_START(rc5),
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
*/
return rc5;
}
static void sms_rc5_parse_word(struct smscore_device_t *coredev)
{
#define RC5_START(x) (((x)>>12)&3)
#define RC5_TOGGLE(x) (((x)>>11)&1)
#define RC5_ADDR(x) (((x)>>6)&0x1F)
#define RC5_INSTR(x) ((x)&0x3F)
int i, j;
u32 rc5_word = 0;
/* Reverse the IR word direction */
for (i = 0 ; i < 28 ; i++)
RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
rc5_word = ir_rc5_decode(rc5_word);
/* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
sms_ir_rc5_event(coredev,
RC5_TOGGLE(rc5_word),
RC5_ADDR(rc5_word),
RC5_INSTR(rc5_word));
}
static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
s32 ir_sample)
{
#define RC5_TIME_GRANULARITY 200
#define RC5_DEF_BIT_TIME 889
#define RC5_MAX_SAME_BIT_CONT 4
#define RC5_WORD_LEN 27 /* 28 bit */
u32 i, j;
s32 delta_time;
u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
u32 level = (ir_sample < 0) ? 0 : 1;
for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
if (delta_time < 0)
continue; /* not so many consecutive bits */
if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
/* timeout */
if (ir_pos == (RC5_WORD_LEN-1))
/* complete last bit */
RC5_PUSH_BIT(ir_word, level, ir_pos)
if (ir_pos == RC5_WORD_LEN)
sms_rc5_parse_word(coredev);
else if (ir_pos) /* timeout within a word */
sms_log("IR error parsing a word");
ir_pos = 0;
ir_word = 0;
/* sms_log("timeout %d", time); */
break;
}
/* The time is within the range of this number of bits */
for (j = 0 ; j < i ; j++)
RC5_PUSH_BIT(ir_word, level, ir_pos)
break;
}
}
void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
{
#define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
u32 i;
enum ir_protocol ir_protocol =
keyboard_layout_maps[coredev->ir.ir_kb_type]
.ir_protocol;
s32 *samples;
int count = len>>2;
samples = (s32 *)buf;
/* sms_log("IR buffer received, length = %d", count);*/
for (i = 0; i < count; i++)
if (ir_protocol == IR_RC5)
sms_rc5_accumulate_bits(coredev, samples[i]);
/* IR_RCMM not implemented */
}
int sms_ir_init(struct smscore_device_t *coredev)
{
struct input_dev *input_dev;
sms_log("Allocating input device");
input_dev = input_allocate_device();
if (!input_dev) {
sms_err("Not enough memory");
return -ENOMEM;
}
coredev->ir.input_dev = input_dev;
coredev->ir.ir_kb_type =
sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
coredev->ir.keyboard_layout_map =
keyboard_layout_maps[coredev->ir.ir_kb_type].
keyboard_layout_map;
sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
sms_log("IR port %d, timeout %d ms",
coredev->ir.controller, coredev->ir.timeout);
snprintf(coredev->ir.name,
IR_DEV_NAME_MAX_LEN,
"SMS IR w/kbd type %d",
coredev->ir.ir_kb_type);
input_dev->name = coredev->ir.name;
input_dev->phys = coredev->ir.name;
input_dev->dev.parent = coredev->device;
/* Key press events only */
input_dev->evbit[0] = BIT_MASK(EV_KEY);
input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
sms_log("Input device (IR) %s is set for key events", input_dev->name);
if (input_register_device(input_dev)) {
sms_err("Failed to register device");
input_free_device(input_dev);
return -EACCES;
}
return 0;
}
void sms_ir_exit(struct smscore_device_t *coredev)
{
if (coredev->ir.input_dev)
input_unregister_device(coredev->ir.input_dev);
sms_log("");
}

View file

@ -0,0 +1,93 @@
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#ifndef __SMS_IR_H__
#define __SMS_IR_H__
#include <linux/input.h>
#define IR_DEV_NAME_MAX_LEN 23 /* "SMS IR kbd type nn\0" */
#define IR_KEYBOARD_LAYOUT_SIZE 64
#define IR_DEFAULT_TIMEOUT 100
enum ir_kb_type {
SMS_IR_KB_DEFAULT_TV,
SMS_IR_KB_HCW_SILVER
};
enum rc5_keyboard_address {
KEYBOARD_ADDRESS_TV1 = 0,
KEYBOARD_ADDRESS_TV2 = 1,
KEYBOARD_ADDRESS_TELETEXT = 2,
KEYBOARD_ADDRESS_VIDEO = 3,
KEYBOARD_ADDRESS_LV1 = 4,
KEYBOARD_ADDRESS_VCR1 = 5,
KEYBOARD_ADDRESS_VCR2 = 6,
KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
KEYBOARD_ADDRESS_SAT1 = 8,
KEYBOARD_ADDRESS_CAMERA = 9,
KEYBOARD_ADDRESS_SAT2 = 10,
KEYBOARD_ADDRESS_CDV = 12,
KEYBOARD_ADDRESS_CAMCORDER = 13,
KEYBOARD_ADDRESS_PRE_AMP = 16,
KEYBOARD_ADDRESS_TUNER = 17,
KEYBOARD_ADDRESS_RECORDER1 = 18,
KEYBOARD_ADDRESS_PRE_AMP1 = 19,
KEYBOARD_ADDRESS_CD_PLAYER = 20,
KEYBOARD_ADDRESS_PHONO = 21,
KEYBOARD_ADDRESS_SATA = 22,
KEYBOARD_ADDRESS_RECORDER2 = 23,
KEYBOARD_ADDRESS_CDR = 26,
KEYBOARD_ADDRESS_LIGHTING = 29,
KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
KEYBOARD_ADDRESS_PHONE = 31,
KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
};
enum ir_protocol {
IR_RC5,
IR_RCMM
};
struct keyboard_layout_map_t {
enum ir_protocol ir_protocol;
enum rc5_keyboard_address rc5_kbd_address;
u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
};
struct smscore_device_t;
struct ir_t {
struct input_dev *input_dev;
enum ir_kb_type ir_kb_type;
char name[IR_DEV_NAME_MAX_LEN+1];
u16 *keyboard_layout_map;
u32 timeout;
u32 controller;
};
int sms_ir_init(struct smscore_device_t *coredev);
void sms_ir_exit(struct smscore_device_t *coredev);
void sms_ir_event(struct smscore_device_t *coredev,
const char *buf, int len);
#endif /* __SMS_IR_H__ */

View file

@ -0,0 +1,357 @@
/*
* smssdio.c - Siano 1xxx SDIO interface driver
*
* Copyright 2008 Pierre Ossman
*
* Based on code by Siano Mobile Silicon, Inc.,
* Copyright (C) 2006-2008, Uri Shkolnik
*
* 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 hardware is a bit odd in that all transfers should be done
* to/from the SMSSDIO_DATA register, yet the "increase address" bit
* always needs to be set.
*
* Also, buffers from the card are always aligned to 128 byte
* boundaries.
*/
/*
* General cleanup notes:
*
* - only typedefs should be name *_t
*
* - use ERR_PTR and friends for smscore_register_device()
*
* - smscore_getbuffer should zero fields
*
* Fix stop command
*/
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include "smscoreapi.h"
#include "sms-cards.h"
/* Registers */
#define SMSSDIO_DATA 0x00
#define SMSSDIO_INT 0x04
static const struct sdio_device_id smssdio_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
.driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
.driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
.driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
.driver_data = SMS1XXX_BOARD_SIANO_VEGA},
{SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
.driver_data = SMS1XXX_BOARD_SIANO_VEGA},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, smssdio_ids);
struct smssdio_device {
struct sdio_func *func;
struct smscore_device_t *coredev;
struct smscore_buffer_t *split_cb;
};
/*******************************************************************/
/* Siano core callbacks */
/*******************************************************************/
static int smssdio_sendrequest(void *context, void *buffer, size_t size)
{
int ret;
struct smssdio_device *smsdev;
smsdev = context;
sdio_claim_host(smsdev->func);
while (size >= smsdev->func->cur_blksize) {
ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1);
if (ret)
goto out;
buffer += smsdev->func->cur_blksize;
size -= smsdev->func->cur_blksize;
}
if (size) {
ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA,
buffer, size);
}
out:
sdio_release_host(smsdev->func);
return ret;
}
/*******************************************************************/
/* SDIO callbacks */
/*******************************************************************/
static void smssdio_interrupt(struct sdio_func *func)
{
int ret, isr;
struct smssdio_device *smsdev;
struct smscore_buffer_t *cb;
struct SmsMsgHdr_ST *hdr;
size_t size;
smsdev = sdio_get_drvdata(func);
/*
* The interrupt register has no defined meaning. It is just
* a way of turning of the level triggered interrupt.
*/
isr = sdio_readb(func, SMSSDIO_INT, &ret);
if (ret) {
dev_err(&smsdev->func->dev,
"Unable to read interrupt register!\n");
return;
}
if (smsdev->split_cb == NULL) {
cb = smscore_getbuffer(smsdev->coredev);
if (!cb) {
dev_err(&smsdev->func->dev,
"Unable to allocate data buffer!\n");
return;
}
ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1);
if (ret) {
dev_err(&smsdev->func->dev,
"Error %d reading initial block!\n", ret);
return;
}
hdr = cb->p;
if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
smsdev->split_cb = cb;
return;
}
size = hdr->msgLength - smsdev->func->cur_blksize;
} else {
cb = smsdev->split_cb;
hdr = cb->p;
size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
smsdev->split_cb = NULL;
}
if (hdr->msgLength > smsdev->func->cur_blksize) {
void *buffer;
size = ALIGN(size, 128);
buffer = cb->p + hdr->msgLength;
BUG_ON(smsdev->func->cur_blksize != 128);
/*
* First attempt to transfer all of it in one go...
*/
ret = sdio_read_blocks(smsdev->func, buffer,
SMSSDIO_DATA, size / 128);
if (ret && ret != -EINVAL) {
smscore_putbuffer(smsdev->coredev, cb);
dev_err(&smsdev->func->dev,
"Error %d reading data from card!\n", ret);
return;
}
/*
* ..then fall back to one block at a time if that is
* not possible...
*
* (we have to do this manually because of the
* problem with the "increase address" bit)
*/
if (ret == -EINVAL) {
while (size) {
ret = sdio_read_blocks(smsdev->func,
buffer, SMSSDIO_DATA, 1);
if (ret) {
smscore_putbuffer(smsdev->coredev, cb);
dev_err(&smsdev->func->dev,
"Error %d reading "
"data from card!\n", ret);
return;
}
buffer += smsdev->func->cur_blksize;
if (size > smsdev->func->cur_blksize)
size -= smsdev->func->cur_blksize;
else
size = 0;
}
}
}
cb->size = hdr->msgLength;
cb->offset = 0;
smscore_onresponse(smsdev->coredev, cb);
}
static int smssdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int ret;
int board_id;
struct smssdio_device *smsdev;
struct smsdevice_params_t params;
board_id = id->driver_data;
smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
if (!smsdev)
return -ENOMEM;
smsdev->func = func;
memset(&params, 0, sizeof(struct smsdevice_params_t));
params.device = &func->dev;
params.buffer_size = 0x5000; /* ?? */
params.num_buffers = 22; /* ?? */
params.context = smsdev;
snprintf(params.devpath, sizeof(params.devpath),
"sdio\\%s", sdio_func_id(func));
params.sendrequest_handler = smssdio_sendrequest;
params.device_type = sms_get_board(board_id)->type;
if (params.device_type != SMS_STELLAR)
params.flags |= SMS_DEVICE_FAMILY2;
else {
/*
* FIXME: Stellar needs special handling...
*/
ret = -ENODEV;
goto free;
}
ret = smscore_register_device(&params, &smsdev->coredev);
if (ret < 0)
goto free;
smscore_set_board_id(smsdev->coredev, board_id);
sdio_claim_host(func);
ret = sdio_enable_func(func);
if (ret)
goto release;
ret = sdio_set_block_size(func, 128);
if (ret)
goto disable;
ret = sdio_claim_irq(func, smssdio_interrupt);
if (ret)
goto disable;
sdio_set_drvdata(func, smsdev);
sdio_release_host(func);
ret = smscore_start_device(smsdev->coredev);
if (ret < 0)
goto reclaim;
return 0;
reclaim:
sdio_claim_host(func);
sdio_release_irq(func);
disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
smscore_unregister_device(smsdev->coredev);
free:
kfree(smsdev);
return ret;
}
static void smssdio_remove(struct sdio_func *func)
{
struct smssdio_device *smsdev;
smsdev = sdio_get_drvdata(func);
/* FIXME: racy! */
if (smsdev->split_cb)
smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
smscore_unregister_device(smsdev->coredev);
sdio_claim_host(func);
sdio_release_irq(func);
sdio_disable_func(func);
sdio_release_host(func);
kfree(smsdev);
}
static struct sdio_driver smssdio_driver = {
.name = "smssdio",
.id_table = smssdio_ids,
.probe = smssdio_probe,
.remove = smssdio_remove,
};
/*******************************************************************/
/* Module functions */
/*******************************************************************/
int smssdio_module_init(void)
{
int ret = 0;
printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
ret = sdio_register_driver(&smssdio_driver);
return ret;
}
void smssdio_module_exit(void)
{
sdio_unregister_driver(&smssdio_driver);
}
module_init(smssdio_module_init);
module_exit(smssdio_module_exit);
MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
MODULE_AUTHOR("Pierre Ossman");
MODULE_LICENSE("GPL");

View file

@ -1,23 +1,23 @@
/*
* Driver for the Siano SMS1xxx USB dongle
*
* author: Anatoly Greenblat
*
* Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
*
* 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.
*/
/****************************************************************
Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
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, see <http://www.gnu.org/licenses/>.
****************************************************************/
#include <linux/kernel.h>
#include <linux/init.h>
@ -26,6 +26,7 @@
#include "smscoreapi.h"
#include "sms-cards.h"
#include "smsendian.h"
static int sms_dbg;
module_param_named(debug, sms_dbg, int, 0644);
@ -64,15 +65,16 @@ static void smsusb_onresponse(struct urb *urb)
struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
struct smsusb_device_t *dev = surb->dev;
if (urb->status < 0) {
sms_err("error, urb status %d, %d bytes",
if (urb->status == -ESHUTDOWN) {
sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
urb->status, urb->actual_length);
return;
}
if (urb->actual_length > 0) {
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
if ((urb->actual_length > 0) && (urb->status == 0)) {
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
smsendian_handle_message_header(phdr);
if (urb->actual_length >= phdr->msgLength) {
surb->cb->size = phdr->msgLength;
@ -109,7 +111,10 @@ static void smsusb_onresponse(struct urb *urb)
"msglen %d actual %d",
phdr->msgLength, urb->actual_length);
}
}
} else
sms_err("error, urb status %d, %d bytes",
urb->status, urb->actual_length);
exit_and_resubmit:
smsusb_submit_urb(dev, surb);
@ -176,6 +181,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
int dummy;
smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
buffer, size, &dummy, 1000);
}
@ -333,8 +339,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
case SMS_VEGA:
dev->buffer_size = USB2_BUFFER_SIZE;
dev->response_alignment =
dev->udev->ep_in[1]->desc.wMaxPacketSize -
sizeof(struct SmsMsgHdr_ST);
le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
sizeof(struct SmsMsgHdr_ST);
params.flags |= SMS_DEVICE_FAMILY2;
break;
@ -479,7 +485,6 @@ static int smsusb_resume(struct usb_interface *intf)
}
struct usb_device_id smsusb_id_table[] = {
#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
{ USB_DEVICE(0x187f, 0x0010),
.driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
{ USB_DEVICE(0x187f, 0x0100),
@ -490,7 +495,6 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
{ USB_DEVICE(0x187f, 0x0300),
.driver_info = SMS1XXX_BOARD_SIANO_VEGA },
#endif
{ USB_DEVICE(0x2040, 0x1700),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
{ USB_DEVICE(0x2040, 0x1800),
@ -521,8 +525,13 @@ struct usb_device_id smsusb_id_table[] = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0x5590),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ } /* Terminating entry */
};
{ USB_DEVICE(0x187f, 0x0202),
.driver_info = SMS1XXX_BOARD_SIANO_NICE },
{ USB_DEVICE(0x187f, 0x0301),
.driver_info = SMS1XXX_BOARD_SIANO_VENICE },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, smsusb_id_table);
static struct usb_driver smsusb_driver = {
@ -548,14 +557,14 @@ int smsusb_module_init(void)
void smsusb_module_exit(void)
{
sms_debug("");
/* Regular USB Cleanup */
usb_deregister(&smsusb_driver);
sms_info("end");
}
module_init(smsusb_module_init);
module_exit(smsusb_module_exit);
MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
MODULE_LICENSE("GPL");

View file

@ -89,6 +89,7 @@
static void p_to_t(u8 const *buf, long int length, u16 pid,
u8 *counter, struct dvb_demux_feed *feed);
static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
break;
}
if (!ret)
ret = av7110->playing;
return ret;
}
@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
aux_ring_buffer_write(&av7110->aout, buf, count);
}
#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
struct dvb_ringbuffer *rb;
u8 *kb;
unsigned long todo = count;
dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
rb = (type) ? &av7110->avout : &av7110->aout;
kb = av7110->kbuf[type];
if (!kb)
return -ENOBUFS;
if (nonblock && !FREE_COND_TS)
return -EWOULDBLOCK;
while (todo >= TS_SIZE) {
if (!FREE_COND_TS) {
if (nonblock)
return count - todo;
if (wait_event_interruptible(rb->queue, FREE_COND_TS))
return count - todo;
}
if (copy_from_user(kb, buf, TS_SIZE))
return -EFAULT;
write_ts_to_decoder(av7110, type, kb, TS_SIZE);
todo -= TS_SIZE;
buf += TS_SIZE;
}
return count - todo;
}
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
}
static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
{
struct ipack *ipack = &av7110->ipack[type];
if (buf[1] & TRANS_ERROR) {
av7110_ipack_reset(ipack);
return -1;
}
if (!(buf[3] & PAYLOAD))
return -1;
if (buf[1] & PAY_START)
av7110_ipack_flush(ipack);
if (buf[3] & ADAPT_FIELD) {
len -= buf[4] + 1;
buf += buf[4] + 1;
if (!len)
return 0;
}
av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
return 0;
}
int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = (struct av7110 *) demux->priv;
struct ipack *ipack = &av7110->ipack[feed->pes_type];
dprintk(2, "av7110:%p, \n", av7110);
@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
return -1;
}
if (!(buf[3] & 0x10)) /* no payload? */
return -1;
if (buf[1] & 0x40)
av7110_ipack_flush(ipack);
if (buf[3] & 0x20) { /* adaptation field? */
len -= buf[4] + 1;
buf += buf[4] + 1;
if (!len)
return 0;
}
av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]);
return 0;
return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
}
@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
unsigned char c;
dprintk(2, "av7110:%p, \n", av7110);
@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
return -EPERM;
return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
if (get_user(c, buf))
return -EFAULT;
if (c == 0x47 && count % TS_SIZE == 0)
return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
else
return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
}
static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
unsigned char c;
dprintk(2, "av7110:%p, \n", av7110);
@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
printk(KERN_ERR "not audio source memory\n");
return -EPERM;
}
return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
if (get_user(c, buf))
return -EFAULT;
if (c == 0x47 && count % TS_SIZE == 0)
return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
else
return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
}
static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
if (ret)
break;
}
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
if (av7110->playing == RP_AV) {
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_SET_DISPLAY_FORMAT:
{
video_displayformat_t format = (video_displayformat_t) arg;
switch (format) {
case VIDEO_PAN_SCAN:
av7110->display_panscan = VID_PAN_SCAN_PREF;
break;
case VIDEO_LETTER_BOX:
av7110->display_panscan = VID_VC_AND_PS_PREF;
break;
case VIDEO_CENTER_CUT_OUT:
av7110->display_panscan = VID_CENTRE_CUT_PREF;
break;
default:
ret = -EINVAL;
}
@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_SLOWMOTION:
if (av7110->playing&RP_VIDEO) {
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
if (av7110->trickmode != TRICK_SLOW)
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
if (!ret)
ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
} else {
@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_CLEAR_BUFFER:
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
av7110_ipack_reset(&av7110->ipack[1]);
if (av7110->playing == RP_AV) {
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
__Play, 2, AV_PES, 0);
@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
break;
case VIDEO_SET_STREAMTYPE:
break;
default:
ret = -ENOIOCTLCMD;
break;
}
return ret;
}
@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
case AUDIO_CHANNEL_SELECT:
av7110->audiostate.channel_select = (audio_channel_select_t) arg;
switch(av7110->audiostate.channel_select) {
case AUDIO_STEREO:
ret = audcom(av7110, AUDIO_CMD_STEREO);
@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
}
break;
case AUDIO_MONO_LEFT:
ret = audcom(av7110, AUDIO_CMD_MONO_L);
if (!ret) {
@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
}
break;
case AUDIO_MONO_RIGHT:
ret = audcom(av7110, AUDIO_CMD_MONO_R);
if (!ret) {
@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
}
break;
default:
ret = -EINVAL;
break;
@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
__Play, 2, AV_PES, 0);
break;
case AUDIO_SET_ID:
case AUDIO_SET_ID:
break;
case AUDIO_SET_MIXER:
{
struct audio_mixer *amix = (struct audio_mixer *)parg;
ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
break;
}
case AUDIO_SET_STREAMTYPE:
break;
default:
ret = -ENOIOCTLCMD;
}
return ret;
}

View file

@ -1089,7 +1089,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
else {
int i, len = dc->x0-dc->color+1;
u8 __user *colors = (u8 __user *)dc->data;
u8 r, g, b, blend;
u8 r, g = 0, b = 0, blend = 0;
ret = 0;
for (i = 0; i<len; i++) {
if (get_user(r, colors + i * 4) ||

View file

@ -458,7 +458,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
if (av7110->analog_tuner_flags) {
if (i->index < 0 || i->index >= 4)
if (i->index >= 4)
return -EINVAL;
} else {
if (i->index != 0)

View file

@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
if (i->index < 0 || i->index >= KNC1_INPUTS)
if (i->index >= KNC1_INPUTS)
return -EINVAL;
memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
return 0;

View file

@ -47,6 +47,9 @@
#include "bsru6.h"
#include "bsbe1.h"
#include "tdhd1.h"
#include "stv6110x.h"
#include "stv090x.h"
#include "isl6423.h"
static int diseqc_method;
module_param(diseqc_method, int, 0444);
@ -425,6 +428,44 @@ static u8 read_pwm(struct budget* budget)
return pwm;
}
static struct stv090x_config tt1600_stv090x_config = {
.device = STV0903,
.demod_mode = STV090x_SINGLE,
.clk_mode = STV090x_CLK_EXT,
.xtal = 27000000,
.address = 0x68,
.ref_clk = 27000000,
.ts1_mode = STV090x_TSMODE_DVBCI,
.ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,
.repeater_level = STV090x_RPTLEVEL_16,
.tuner_init = NULL,
.tuner_set_mode = NULL,
.tuner_set_frequency = NULL,
.tuner_get_frequency = NULL,
.tuner_set_bandwidth = NULL,
.tuner_get_bandwidth = NULL,
.tuner_set_bbgain = NULL,
.tuner_get_bbgain = NULL,
.tuner_set_refclk = NULL,
.tuner_get_status = NULL,
};
static struct stv6110x_config tt1600_stv6110x_config = {
.addr = 0x60,
.refclk = 27000000,
};
static struct isl6423_config tt1600_isl6423_config = {
.current_max = SEC_CURRENT_515m,
.curlim = SEC_CURRENT_LIM_ON,
.mod_extern = 1,
.addr = 0x08,
};
static void frontend_init(struct budget *budget)
{
(void)alps_bsbe1_config; /* avoid warning */
@ -566,6 +607,48 @@ static void frontend_init(struct budget *budget)
}
break;
}
case 0x101c: { /* TT S2-1600 */
struct stv6110x_devctl *ctl;
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
msleep(50);
saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
msleep(250);
budget->dvb_frontend = dvb_attach(stv090x_attach,
&tt1600_stv090x_config,
&budget->i2c_adap,
STV090x_DEMODULATOR_0);
if (budget->dvb_frontend) {
ctl = dvb_attach(stv6110x_attach,
budget->dvb_frontend,
&tt1600_stv6110x_config,
&budget->i2c_adap);
tt1600_stv090x_config.tuner_init = ctl->tuner_init;
tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;
tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;
tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;
tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;
tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status;
dvb_attach(isl6423_attach,
budget->dvb_frontend,
&budget->i2c_adap,
&tt1600_isl6423_config);
} else {
dvb_frontend_detach(budget->dvb_frontend);
budget->dvb_frontend = NULL;
}
}
break;
}
if (budget->dvb_frontend == NULL) {
@ -641,6 +724,7 @@ MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
@ -653,6 +737,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),

View file

@ -33,6 +33,10 @@
History:
Version 0.46:
Removed usb_dsbr100_open/close calls and radio->users counter. Also,
radio->muted changed to radio->status and suspend/resume calls updated.
Version 0.45:
Converted to v4l2_device.
@ -100,8 +104,8 @@
*/
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#define DRIVER_VERSION "v0.45"
#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
#define DRIVER_VERSION "v0.46"
#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@ -121,13 +125,15 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
/* defines for radio->status */
#define STARTED 0
#define STOPPED 1
#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void usb_dsbr100_disconnect(struct usb_interface *intf);
static int usb_dsbr100_open(struct file *file);
static int usb_dsbr100_close(struct file *file);
static int usb_dsbr100_suspend(struct usb_interface *intf,
pm_message_t message);
static int usb_dsbr100_resume(struct usb_interface *intf);
@ -145,9 +151,8 @@ struct dsbr100_device {
struct mutex lock; /* buffer locking */
int curfreq;
int stereo;
int users;
int removed;
int muted;
int status;
};
static struct usb_device_id usb_dsbr100_device_table [] = {
@ -201,7 +206,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
goto usb_control_msg_failed;
}
radio->muted = 0;
radio->status = STARTED;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
@ -244,7 +249,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
goto usb_control_msg_failed;
}
radio->muted = 1;
radio->status = STOPPED;
mutex_unlock(&radio->lock);
return (radio->transfer_buffer)[0];
@ -258,12 +263,12 @@ usb_control_msg_failed:
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
static int dsbr100_setfreq(struct dsbr100_device *radio)
{
int retval;
int request;
int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
freq = (freq / 16 * 80) / 1000 + 856;
mutex_lock(&radio->lock);
retval = usb_control_msg(radio->usbdev,
@ -431,7 +436,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
radio->curfreq = f->frequency;
mutex_unlock(&radio->lock);
retval = dsbr100_setfreq(radio, radio->curfreq);
retval = dsbr100_setfreq(radio);
if (retval < 0)
dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
return 0;
@ -473,7 +478,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
ctrl->value = radio->muted;
ctrl->value = radio->status;
return 0;
}
return -EINVAL;
@ -543,65 +548,27 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
static int usb_dsbr100_open(struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
lock_kernel();
radio->users = 1;
radio->muted = 1;
retval = dsbr100_start(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"Radio did not start up properly\n");
radio->users = 0;
unlock_kernel();
return -EIO;
}
retval = dsbr100_setfreq(radio, radio->curfreq);
if (retval < 0)
dev_warn(&radio->usbdev->dev,
"set frequency failed\n");
unlock_kernel();
return 0;
}
static int usb_dsbr100_close(struct file *file)
{
struct dsbr100_device *radio = video_drvdata(file);
int retval;
if (!radio)
return -ENODEV;
mutex_lock(&radio->lock);
radio->users = 0;
mutex_unlock(&radio->lock);
if (!radio->removed) {
retval = dsbr100_stop(radio);
if (retval < 0) {
dev_warn(&radio->usbdev->dev,
"dsbr100_stop failed\n");
}
}
return 0;
}
/* Suspend device - stop device. */
static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
retval = dsbr100_stop(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_stop failed\n");
if (radio->status == STARTED) {
retval = dsbr100_stop(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_stop failed\n");
/* After dsbr100_stop() status set to STOPPED.
* If we want driver to start radio on resume
* we set status equal to STARTED.
* On resume we will check status and run radio if needed.
*/
mutex_lock(&radio->lock);
radio->status = STARTED;
mutex_unlock(&radio->lock);
}
dev_info(&intf->dev, "going into suspend..\n");
@ -614,9 +581,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
struct dsbr100_device *radio = usb_get_intfdata(intf);
int retval;
retval = dsbr100_start(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_start failed\n");
if (radio->status == STARTED) {
retval = dsbr100_start(radio);
if (retval < 0)
dev_warn(&intf->dev, "dsbr100_start failed\n");
}
dev_info(&intf->dev, "coming out of suspend..\n");
@ -636,8 +605,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
/* File system interface */
static const struct v4l2_file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
.open = usb_dsbr100_open,
.release = usb_dsbr100_close,
.ioctl = video_ioctl2,
};
@ -695,9 +662,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
mutex_init(&radio->lock);
radio->removed = 0;
radio->users = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
radio->status = STOPPED;
video_set_drvdata(&radio->videodev, radio);

View file

@ -64,6 +64,7 @@
#include <media/v4l2-ioctl.h>
#include <linux/usb.h>
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#include <linux/mutex.h>
/* driver and module definitions */
#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"

View file

@ -49,7 +49,6 @@ struct fmi
int io;
int curvol; /* 1 or 0 */
unsigned long curfreq; /* freq in kHz */
__u32 flags;
struct mutex lock;
};
@ -57,7 +56,7 @@ static struct fmi fmi_card;
static struct pnp_dev *dev;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
/* It is only useful to give freq in interval of 800 (=0.05Mhz),
* other bits will be truncated, e.g 92.7400016 -> 92.7, but
* 92.7400017 -> 92.75
*/
@ -142,7 +141,6 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
int mult;
struct fmi *fmi = video_drvdata(file);
if (v->index > 0)
@ -150,11 +148,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
strlcpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
v->rangelow = RSF16_MINFREQ / mult;
v->rangehigh = RSF16_MAXFREQ / mult;
v->rangelow = RSF16_MINFREQ;
v->rangehigh = RSF16_MAXFREQ;
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
v->audmode = V4L2_TUNER_MODE_STEREO;
v->signal = fmi_getsigstr(fmi);
return 0;
@ -171,8 +168,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
{
struct fmi *fmi = video_drvdata(file);
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
f->frequency *= 1000;
if (f->frequency < RSF16_MINFREQ ||
f->frequency > RSF16_MAXFREQ)
return -EINVAL;
@ -189,8 +184,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
f->type = V4L2_TUNER_RADIO;
f->frequency = fmi->curfreq;
if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
f->frequency /= 1000;
return 0;
}
@ -347,7 +340,6 @@ static int __init fmi_init(void)
return res;
}
fmi->flags = V4L2_TUNER_CAP_LOW;
strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
fmi->vdev.v4l2_dev = v4l2_dev;
fmi->vdev.fops = &fmi_fops;

View file

@ -61,13 +61,12 @@ struct fmr2
int stereo; /* card is producing stereo audio */
unsigned long curfreq; /* freq in kHz */
int card_type;
u32 flags;
};
static struct fmr2 fmr2_card;
/* hw precision is 12.5 kHz
* It is only useful to give freq in intervall of 200 (=0.0125Mhz),
* It is only useful to give freq in interval of 200 (=0.0125Mhz),
* other bits will be truncated
*/
#define RSF16_ENCODE(x) ((x) / 200 + 856)
@ -221,7 +220,6 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
int mult;
struct fmr2 *fmr2 = video_drvdata(file);
if (v->index > 0)
@ -230,13 +228,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
strlcpy(v->name, "FM", sizeof(v->name));
v->type = V4L2_TUNER_RADIO;
mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
v->rangelow = RSF16_MINFREQ / mult;
v->rangehigh = RSF16_MAXFREQ / mult;
v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
V4L2_TUNER_MODE_MONO;
v->rangelow = RSF16_MINFREQ;
v->rangehigh = RSF16_MAXFREQ;
v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
V4L2_TUNER_SUB_MONO;
v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
v->audmode = V4L2_TUNER_MODE_STEREO;
mutex_lock(&fmr2->lock);
v->signal = fmr2_getsigstr(fmr2);
mutex_unlock(&fmr2->lock);
@ -254,8 +251,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
{
struct fmr2 *fmr2 = video_drvdata(file);
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
f->frequency *= 1000;
if (f->frequency < RSF16_MINFREQ ||
f->frequency > RSF16_MAXFREQ)
return -EINVAL;
@ -279,8 +274,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
f->type = V4L2_TUNER_RADIO;
f->frequency = fmr2->curfreq;
if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
f->frequency /= 1000;
return 0;
}
@ -406,7 +399,6 @@ static int __init fmr2_init(void)
strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
fmr2->io = io;
fmr2->stereo = 1;
fmr2->flags = V4L2_TUNER_CAP_LOW;
mutex_init(&fmr2->lock);
if (!request_region(fmr2->io, 2, "sf16fmr2")) {

View file

@ -1214,7 +1214,6 @@ static int si470x_fops_release(struct file *file)
usb_autopm_put_interface(radio->intf);
}
unlock:
mutex_unlock(&radio->disconnect_lock);
done:

View file

@ -440,6 +440,24 @@ config VIDEO_ADV7175
To compile this driver as a module, choose M here: the
module will be called adv7175.
config VIDEO_THS7303
tristate "THS7303 Video Amplifier"
depends on I2C
help
Support for TI THS7303 video amplifier
To compile this driver as a module, choose M here: the
module will be called ths7303.
config VIDEO_ADV7343
tristate "ADV7343 video encoder"
depends on I2C
help
Support for Analog Devices I2C bus based ADV7343 encoder.
To compile this driver as a module, choose M here: the
module will be called adv7343.
comment "Video improvement chips"
config VIDEO_UPD64031A
@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC
config SOC_CAMERA
tristate "SoC camera support"
depends on VIDEO_V4L2 && HAS_DMA
depends on VIDEO_V4L2 && HAS_DMA && I2C
select VIDEOBUF_GEN
help
SoC Camera is a common API to several cameras, not connecting

View file

@ -12,6 +12,8 @@ omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o
# V4L2 core modules
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
ifeq ($(CONFIG_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
# All i2c modules must come first:
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
obj-$(CONFIG_VIDEO_W9966) += w9966.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@ -49,16 +45,47 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
obj-$(CONFIG_VIDEO_BT856) += bt856.o
obj-$(CONFIG_VIDEO_BT866) += bt866.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
obj-$(CONFIG_VIDEO_VINO) += indycam.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
# And now the v4l2 drivers:
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
obj-$(CONFIG_VIDEO_W9966) += w9966.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
obj-$(CONFIG_VIDEO_VINO) += vino.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@ -69,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
@ -92,19 +109,12 @@ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
@ -134,24 +144,21 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
# soc-camera host drivers have to be linked after camera drivers
obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners

View file

@ -0,0 +1,534 @@
/*
* adv7343 - ADV7343 Video Encoder Driver
*
* The encoder hardware does not support SECAM.
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ctype.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/videodev2.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <media/adv7343.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include "adv7343_regs.h"
MODULE_DESCRIPTION("ADV7343 video encoder driver");
MODULE_LICENSE("GPL");
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level 0-1");
struct adv7343_state {
struct v4l2_subdev sd;
u8 reg00;
u8 reg01;
u8 reg02;
u8 reg35;
u8 reg80;
u8 reg82;
int bright;
int hue;
int gain;
u32 output;
v4l2_std_id std;
};
static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
{
return container_of(sd, struct adv7343_state, sd);
}
static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
return i2c_smbus_write_byte_data(client, reg, value);
}
static const u8 adv7343_init_reg_val[] = {
ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
};
/*
* 2^32
* FSC(reg) = FSC (HZ) * --------
* 27000000
*/
static const struct adv7343_std_info stdinfo[] = {
{
/* FSC(Hz) = 3,579,545.45 Hz */
SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
}, {
/* FSC(Hz) = 3,575,611.00 Hz */
SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
}, {
/* FSC(Hz) = 3,582,056.00 */
SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
}, {
/* FSC(Hz) = 4,433,618.75 Hz */
SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
}, {
/* FSC(Hz) = 4,433,618.75 Hz */
SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
}, {
/* FSC(Hz) = 4,433,618.75 Hz */
SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
}, {
/* FSC(Hz) = 4,433,618.75 Hz */
SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
},
};
static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7343_state *state = to_state(sd);
struct adv7343_std_info *std_info;
int output_idx, num_std;
char *fsc_ptr;
u8 reg, val;
int err = 0;
int i = 0;
output_idx = state->output;
std_info = (struct adv7343_std_info *)stdinfo;
num_std = ARRAY_SIZE(stdinfo);
for (i = 0; i < num_std; i++) {
if (std_info[i].stdid & std)
break;
}
if (i == num_std) {
v4l2_dbg(1, debug, sd,
"Invalid std or std is not supported: %llx\n",
(unsigned long long)std);
return -EINVAL;
}
/* Set the standard */
val = state->reg80 & (~(SD_STD_MASK));
val |= std_info[i].standard_val3;
err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
if (err < 0)
goto setstd_exit;
state->reg80 = val;
/* Configure the input mode register */
val = state->reg01 & (~((u8) INPUT_MODE_MASK));
val |= SD_INPUT_MODE;
err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
if (err < 0)
goto setstd_exit;
state->reg01 = val;
/* Program the sub carrier frequency registers */
fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
reg = ADV7343_FSC_REG0;
for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
err = adv7343_write(sd, reg, *fsc_ptr);
if (err < 0)
goto setstd_exit;
}
val = state->reg80;
/* Filter settings */
if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
val &= 0x03;
else if (std & ~V4L2_STD_SECAM)
val |= 0x04;
err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
if (err < 0)
goto setstd_exit;
state->reg80 = val;
setstd_exit:
if (err != 0)
v4l2_err(sd, "Error setting std, write failed\n");
return err;
}
static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
{
struct adv7343_state *state = to_state(sd);
unsigned char val;
int err = 0;
if (output_type > ADV7343_SVIDEO_ID) {
v4l2_dbg(1, debug, sd,
"Invalid output type or output type not supported:%d\n",
output_type);
return -EINVAL;
}
/* Enable Appropriate DAC */
val = state->reg00 & 0x03;
if (output_type == ADV7343_COMPOSITE_ID)
val |= ADV7343_COMPOSITE_POWER_VALUE;
else if (output_type == ADV7343_COMPONENT_ID)
val |= ADV7343_COMPONENT_POWER_VALUE;
else
val |= ADV7343_SVIDEO_POWER_VALUE;
err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
if (err < 0)
goto setoutput_exit;
state->reg00 = val;
/* Enable YUV output */
val = state->reg02 | YUV_OUTPUT_SELECT;
err = adv7343_write(sd, ADV7343_MODE_REG0, val);
if (err < 0)
goto setoutput_exit;
state->reg02 = val;
/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
if (err < 0)
goto setoutput_exit;
state->reg82 = val;
/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
* zero */
val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
if (err < 0)
goto setoutput_exit;
state->reg35 = val;
setoutput_exit:
if (err != 0)
v4l2_err(sd, "Error setting output, write failed\n");
return err;
}
static int adv7343_log_status(struct v4l2_subdev *sd)
{
struct adv7343_state *state = to_state(sd);
v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
((state->output == 1) ? "Component" : "S-Video"));
return 0;
}
static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
ADV7343_BRIGHTNESS_MAX, 1,
ADV7343_BRIGHTNESS_DEF);
case V4L2_CID_HUE:
return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
ADV7343_HUE_MAX, 1 ,
ADV7343_HUE_DEF);
case V4L2_CID_GAIN:
return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
ADV7343_GAIN_MAX, 1,
ADV7343_GAIN_DEF);
default:
break;
}
return 0;
}
static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct adv7343_state *state = to_state(sd);
int err = 0;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
ctrl->value > ADV7343_BRIGHTNESS_MAX) {
v4l2_dbg(1, debug, sd,
"invalid brightness settings %d\n",
ctrl->value);
return -ERANGE;
}
state->bright = ctrl->value;
err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
state->bright);
break;
case V4L2_CID_HUE:
if (ctrl->value < ADV7343_HUE_MIN ||
ctrl->value > ADV7343_HUE_MAX) {
v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
ctrl->value);
return -ERANGE;
}
state->hue = ctrl->value;
err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
break;
case V4L2_CID_GAIN:
if (ctrl->value < ADV7343_GAIN_MIN ||
ctrl->value > ADV7343_GAIN_MAX) {
v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
ctrl->value);
return -ERANGE;
}
if ((ctrl->value > POSITIVE_GAIN_MAX) &&
(ctrl->value < NEGATIVE_GAIN_MIN)) {
v4l2_dbg(1, debug, sd,
"gain settings not within the specified range\n");
return -ERANGE;
}
state->gain = ctrl->value;
err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
break;
default:
return -EINVAL;
}
if (err < 0)
v4l2_err(sd, "Failed to set the encoder controls\n");
return err;
}
static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
struct adv7343_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->value = state->bright;
break;
case V4L2_CID_HUE:
ctrl->value = state->hue;
break;
case V4L2_CID_GAIN:
ctrl->value = state->gain;
break;
default:
return -EINVAL;
}
return 0;
}
static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
}
static const struct v4l2_subdev_core_ops adv7343_core_ops = {
.log_status = adv7343_log_status,
.g_chip_ident = adv7343_g_chip_ident,
.g_ctrl = adv7343_g_ctrl,
.s_ctrl = adv7343_s_ctrl,
.queryctrl = adv7343_queryctrl,
};
static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7343_state *state = to_state(sd);
int err = 0;
if (state->std == std)
return 0;
err = adv7343_setstd(sd, std);
if (!err)
state->std = std;
return err;
}
static int adv7343_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct adv7343_state *state = to_state(sd);
int err = 0;
if (state->output == output)
return 0;
err = adv7343_setoutput(sd, output);
if (!err)
state->output = output;
return err;
}
static const struct v4l2_subdev_video_ops adv7343_video_ops = {
.s_std_output = adv7343_s_std_output,
.s_routing = adv7343_s_routing,
};
static const struct v4l2_subdev_ops adv7343_ops = {
.core = &adv7343_core_ops,
.video = &adv7343_video_ops,
};
static int adv7343_initialize(struct v4l2_subdev *sd)
{
struct adv7343_state *state = to_state(sd);
int err = 0;
int i;
for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
err = adv7343_write(sd, adv7343_init_reg_val[i],
adv7343_init_reg_val[i+1]);
if (err) {
v4l2_err(sd, "Error initializing\n");
return err;
}
}
/* Configure for default video standard */
err = adv7343_setoutput(sd, state->output);
if (err < 0) {
v4l2_err(sd, "Error setting output during init\n");
return -EINVAL;
}
err = adv7343_setstd(sd, state->std);
if (err < 0) {
v4l2_err(sd, "Error setting std during init\n");
return -EINVAL;
}
return err;
}
static int adv7343_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct adv7343_state *state;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
if (state == NULL)
return -ENOMEM;
state->reg00 = 0x80;
state->reg01 = 0x00;
state->reg02 = 0x20;
state->reg35 = 0x00;
state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT;
state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT;
state->output = ADV7343_COMPOSITE_ID;
state->std = V4L2_STD_NTSC;
v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
return adv7343_initialize(&state->sd);
}
static int adv7343_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
kfree(to_state(sd));
return 0;
}
static const struct i2c_device_id adv7343_id[] = {
{"adv7343", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, adv7343_id);
static struct i2c_driver adv7343_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "adv7343",
},
.probe = adv7343_probe,
.remove = adv7343_remove,
.id_table = adv7343_id,
};
static __init int init_adv7343(void)
{
return i2c_add_driver(&adv7343_driver);
}
static __exit void exit_adv7343(void)
{
i2c_del_driver(&adv7343_driver);
}
module_init(init_adv7343);
module_exit(exit_adv7343);

View file

@ -0,0 +1,185 @@
/*
* ADV7343 encoder related structure and register definitions
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ADV7343_REG_H
#define ADV7343_REGS_H
struct adv7343_std_info {
u32 standard_val3;
u32 fsc_val;
v4l2_std_id stdid;
};
/* Register offset macros */
#define ADV7343_POWER_MODE_REG (0x00)
#define ADV7343_MODE_SELECT_REG (0x01)
#define ADV7343_MODE_REG0 (0x02)
#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b)
#define ADV7343_SOFT_RESET (0x17)
#define ADV7343_HD_MODE_REG1 (0x30)
#define ADV7343_HD_MODE_REG2 (0x31)
#define ADV7343_HD_MODE_REG3 (0x32)
#define ADV7343_HD_MODE_REG4 (0x33)
#define ADV7343_HD_MODE_REG5 (0x34)
#define ADV7343_HD_MODE_REG6 (0x35)
#define ADV7343_HD_MODE_REG7 (0x39)
#define ADV7343_SD_MODE_REG1 (0x80)
#define ADV7343_SD_MODE_REG2 (0x82)
#define ADV7343_SD_MODE_REG3 (0x83)
#define ADV7343_SD_MODE_REG4 (0x84)
#define ADV7343_SD_MODE_REG5 (0x86)
#define ADV7343_SD_MODE_REG6 (0x87)
#define ADV7343_SD_MODE_REG7 (0x88)
#define ADV7343_SD_MODE_REG8 (0x89)
#define ADV7343_FSC_REG0 (0x8C)
#define ADV7343_FSC_REG1 (0x8D)
#define ADV7343_FSC_REG2 (0x8E)
#define ADV7343_FSC_REG3 (0x8F)
#define ADV7343_SD_CGMS_WSS0 (0x99)
#define ADV7343_SD_HUE_REG (0xA0)
#define ADV7343_SD_BRIGHTNESS_WSS (0xA1)
/* Default values for the registers */
#define ADV7343_POWER_MODE_REG_DEFAULT (0x10)
#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default
720p EAVSAV code*/
#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data
valid */
#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */
#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */
#define ADV7343_HD_MODE_REG5_DEFAULT (0x08)
#define ADV7343_HD_MODE_REG6_DEFAULT (0x00)
#define ADV7343_HD_MODE_REG7_DEFAULT (0x00)
#define ADV7343_SD_MODE_REG8_DEFAULT (0x00)
#define ADV7343_SOFT_RESET_DEFAULT (0x02)
#define ADV7343_COMPOSITE_POWER_VALUE (0x80)
#define ADV7343_COMPONENT_POWER_VALUE (0x1C)
#define ADV7343_SVIDEO_POWER_VALUE (0x60)
#define ADV7343_SD_HUE_REG_DEFAULT (127)
#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03)
#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10)
#define ADV7343_SD_MODE_REG1_DEFAULT (0x00)
#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9)
#define ADV7343_SD_MODE_REG3_DEFAULT (0x10)
#define ADV7343_SD_MODE_REG4_DEFAULT (0x01)
#define ADV7343_SD_MODE_REG5_DEFAULT (0x02)
#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C)
#define ADV7343_SD_MODE_REG7_DEFAULT (0x04)
#define ADV7343_SD_MODE_REG8_DEFAULT (0x00)
/* Bit masks for Mode Select Register */
#define INPUT_MODE_MASK (0x70)
#define SD_INPUT_MODE (0x00)
#define HD_720P_INPUT_MODE (0x10)
#define HD_1080I_INPUT_MODE (0x10)
/* Bit masks for Mode Register 0 */
#define TEST_PATTERN_BLACK_BAR_EN (0x04)
#define YUV_OUTPUT_SELECT (0x20)
#define RGB_OUTPUT_SELECT (0xDF)
/* Bit masks for DAC output levels */
#define DAC_OUTPUT_LEVEL_MASK (0xFF)
#define POSITIVE_GAIN_MAX (0x40)
#define POSITIVE_GAIN_MIN (0x00)
#define NEGATIVE_GAIN_MAX (0xFF)
#define NEGATIVE_GAIN_MIN (0xC0)
/* Bit masks for soft reset register */
#define SOFT_RESET (0x02)
/* Bit masks for HD Mode Register 1 */
#define OUTPUT_STD_MASK (0x03)
#define OUTPUT_STD_SHIFT (0)
#define OUTPUT_STD_EIA0_2 (0x00)
#define OUTPUT_STD_EIA0_1 (0x01)
#define OUTPUT_STD_FULL (0x02)
#define EMBEDDED_SYNC (0x04)
#define EXTERNAL_SYNC (0xFB)
#define STD_MODE_SHIFT (3)
#define STD_MODE_MASK (0x1F)
#define STD_MODE_720P (0x05)
#define STD_MODE_720P_25 (0x08)
#define STD_MODE_720P_30 (0x07)
#define STD_MODE_720P_50 (0x06)
#define STD_MODE_1080I (0x0D)
#define STD_MODE_1080I_25fps (0x0E)
#define STD_MODE_1080P_24 (0x12)
#define STD_MODE_1080P_25 (0x10)
#define STD_MODE_1080P_30 (0x0F)
#define STD_MODE_525P (0x00)
#define STD_MODE_625P (0x03)
/* Bit masks for SD Mode Register 1 */
#define SD_STD_MASK (0x03)
#define SD_STD_NTSC (0x00)
#define SD_STD_PAL_BDGHI (0x01)
#define SD_STD_PAL_M (0x02)
#define SD_STD_PAL_N (0x03)
#define SD_LUMA_FLTR_MASK (0x7)
#define SD_LUMA_FLTR_SHIFT (0x2)
#define SD_CHROMA_FLTR_MASK (0x7)
#define SD_CHROMA_FLTR_SHIFT (0x5)
/* Bit masks for SD Mode Register 2 */
#define SD_PBPR_SSAF_EN (0x01)
#define SD_PBPR_SSAF_DI (0xFE)
#define SD_DAC_1_DI (0xFD)
#define SD_DAC_2_DI (0xFB)
#define SD_PEDESTAL_EN (0x08)
#define SD_PEDESTAL_DI (0xF7)
#define SD_SQUARE_PIXEL_EN (0x10)
#define SD_SQUARE_PIXEL_DI (0xEF)
#define SD_PIXEL_DATA_VALID (0x40)
#define SD_ACTIVE_EDGE_EN (0x80)
#define SD_ACTIVE_EDGE_DI (0x7F)
/* Bit masks for HD Mode Register 6 */
#define HD_RGB_INPUT_EN (0x02)
#define HD_RGB_INPUT_DI (0xFD)
#define HD_PBPR_SYNC_EN (0x04)
#define HD_PBPR_SYNC_DI (0xFB)
#define HD_DAC_SWAP_EN (0x08)
#define HD_DAC_SWAP_DI (0xF7)
#define HD_GAMMA_CURVE_A (0xEF)
#define HD_GAMMA_CURVE_B (0x10)
#define HD_GAMMA_EN (0x20)
#define HD_GAMMA_DI (0xDF)
#define HD_ADPT_FLTR_MODEB (0x40)
#define HD_ADPT_FLTR_MODEA (0xBF)
#define HD_ADPT_FLTR_EN (0x80)
#define HD_ADPT_FLTR_DI (0x7F)
#define ADV7343_BRIGHTNESS_MAX (127)
#define ADV7343_BRIGHTNESS_MIN (0)
#define ADV7343_BRIGHTNESS_DEF (3)
#define ADV7343_HUE_MAX (255)
#define ADV7343_HUE_MIN (0)
#define ADV7343_HUE_DEF (127)
#define ADV7343_GAIN_MAX (255)
#define ADV7343_GAIN_MIN (0)
#define ADV7343_GAIN_DEF (0)
#endif

View file

@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
/* Tuner Reset Command from xc5000 */
/* Drive the tuner into reset and out */
au0828_clear(dev, REG_001, 2);
mdelay(200);
mdelay(10);
au0828_set(dev, REG_001, 2);
mdelay(50);
mdelay(10);
return 0;
} else {
printk(KERN_ERR

View file

@ -36,6 +36,11 @@ int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
static unsigned int disable_usb_speed_check;
module_param(disable_usb_speed_check, int, 0444);
MODULE_PARM_DESC(disable_usb_speed_check,
"override min bandwidth requirement of 480M bps");
#define _AU0828_BULKPIPE 0x03
#define _BULKPIPESIZE 0xffff
@ -181,6 +186,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
le16_to_cpu(usbdev->descriptor.idProduct),
ifnum);
/*
* Make sure we have 480 Mbps of bandwidth, otherwise things like
* video stream wouldn't likely work, since 12 Mbps is generally
* not enough even for most Digital TV streams.
*/
if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
printk(KERN_ERR "au0828: Device initialization failed.\n");
printk(KERN_ERR "au0828: Device must be connected to a "
"high-speed USB 2.0 port.\n");
return -ENODEV;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);

View file

@ -829,6 +829,9 @@ static int au0828_v4l2_close(struct file *filp)
au0828_uninit_isoc(dev);
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
/* When close the device, set the usb intf0 into alt0 to free
USB bandwidth */
ret = usb_set_interface(dev->usbdev, 0, 0);
@ -910,11 +913,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
(unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
rc);
return rc;
}

View file

@ -3152,6 +3152,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
struct bttv_fh *fh = file->private_data;
struct bttv_buffer *buf;
enum v4l2_field field;
unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@ -3160,9 +3161,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
}
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
mutex_lock(&fh->cap.vb_lock);
/* streaming capture */
if (list_empty(&fh->cap.stream))
return POLLERR;
goto err;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
@ -3191,11 +3193,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
poll_wait(file, &buf->vb.done, wait);
if (buf->vb.state == VIDEOBUF_DONE ||
buf->vb.state == VIDEOBUF_ERROR)
return POLLIN|POLLRDNORM;
return 0;
rc = POLLIN|POLLRDNORM;
else
rc = 0;
err:
mutex_unlock(&fh->cap.vb_lock);
return POLLERR;
return rc;
}
static int bttv_open(struct file *file)
@ -4166,7 +4169,6 @@ static struct video_device *vdev_init(struct bttv *btv,
if (NULL == vfd)
return NULL;
*vfd = *template;
vfd->minor = -1;
vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
vfd->debug = bttv_debug;
@ -4629,7 +4631,7 @@ static int __init bttv_init_module(void)
#endif
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
gbuffers = 2;
if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
if (gbufsize > BTTV_MAX_FBUF)
gbufsize = BTTV_MAX_FBUF;
gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
if (bttv_verbose)

View file

@ -389,6 +389,27 @@ int __devinit init_bttv_i2c(struct bttv *btv)
}
if (0 == btv->i2c_rc && i2c_scan)
do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
/* Instantiate the IR receiver device, if present */
if (0 == btv->i2c_rc) {
struct i2c_board_info info;
/* The external IR receiver is at i2c address 0x34 (0x35 for
reads). Future Hauppauge cards will have an internal
receiver at 0x30 (0x31 for reads). In theory, both can be
fitted, and Hauppauge suggest an external overrides an
internal.
That's why we probe 0x1a (~0x34) first. CB
*/
const unsigned short addr_list[] = {
0x1a, 0x18, 0x4b, 0x64, 0x30,
I2C_CLIENT_END
};
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
}
return btv->i2c_rc;
}

View file

@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
switch(m->id) {
case CPIA2_CID_FLICKER_MODE:
if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
if (m->index >= NUM_FLICKER_CONTROLS)
return -EINVAL;
strcpy(m->name, flicker_controls[m->index].name);
@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
maximum = i;
}
}
if(m->index < 0 || m->index > maximum)
if (m->index > maximum)
return -EINVAL;
strcpy(m->name, framerate_controls[m->index].name);
break;
}
case CPIA2_CID_LIGHTS:
if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
if (m->index >= NUM_LIGHTS_CONTROLS)
return -EINVAL;
strcpy(m->name, lights_controls[m->index].name);

View file

@ -26,14 +26,18 @@
#include "cx18-cards.h"
#include "cx18-audio.h"
#define CX18_AUDIO_ENABLE 0xc72014
#define CX18_AUDIO_ENABLE 0xc72014
#define CX18_AI1_MUX_MASK 0x30
#define CX18_AI1_MUX_I2S1 0x00
#define CX18_AI1_MUX_I2S2 0x10
#define CX18_AI1_MUX_843_I2S 0x20
/* Selects the audio input and output according to the current
settings. */
int cx18_audio_set_io(struct cx18 *cx)
{
const struct cx18_card_audio_input *in;
u32 val;
u32 u, v;
int err;
/* Determine which input to use */
@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx)
return err;
/* FIXME - this internal mux should be abstracted to a subdev */
val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
(in->audio_input << 4);
cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
v = u & ~CX18_AI1_MUX_MASK;
switch (in->audio_input) {
case CX18_AV_AUDIO_SERIAL1:
v |= CX18_AI1_MUX_I2S1;
break;
case CX18_AV_AUDIO_SERIAL2:
v |= CX18_AI1_MUX_I2S2;
break;
default:
v |= CX18_AI1_MUX_843_I2S;
break;
}
if (v == u) {
/* force a toggle of some AI1 MUX control bits */
u &= ~CX18_AI1_MUX_MASK;
switch (in->audio_input) {
case CX18_AV_AUDIO_SERIAL1:
u |= CX18_AI1_MUX_843_I2S;
break;
case CX18_AV_AUDIO_SERIAL2:
u |= CX18_AI1_MUX_843_I2S;
break;
default:
u |= CX18_AI1_MUX_I2S1;
break;
}
cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
u, CX18_AI1_MUX_MASK);
}
cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
v, CX18_AI1_MUX_MASK);
return 0;
}

View file

@ -99,9 +99,39 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
or_value);
}
static void cx18_av_initialize(struct cx18 *cx)
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
{
struct cx18_av_state *state = &cx->av_state;
struct cx18 *cx = v4l2_get_subdevdata(sd);
/*
* The crystal freq used in calculations in this driver will be
* 28.636360 MHz.
* Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
*/
/*
* VDCLK Integer = 0x0f, Post Divider = 0x04
* AIMCLK Integer = 0x0e, Post Divider = 0x16
*/
cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
/* VDCLK Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
/* AIMCLK Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
return 0;
}
static void cx18_av_initialize(struct v4l2_subdev *sd)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
u32 v;
cx18_av_loadfw(cx);
@ -150,6 +180,26 @@ static void cx18_av_initialize(struct cx18 *cx)
cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
/*
* Disable Video Auto-config of the Analog Front End and Video PLL.
*
* Since we only use BT.656 pixel mode, which works for both 525 and 625
* line systems, it's just easier for us to set registers
* 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL),
* 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC)
* ourselves, than to run around cleaning up after the auto-config.
*
* (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit
* get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL
* autoconfig either.)
*
* As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3.
*/
cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
/* Setup the Video and and Aux/Audio PLLs */
cx18_av_init(sd, 0);
/* set video to auto-detect */
/* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
/* set the comb notch = 1 */
@ -176,12 +226,23 @@ static void cx18_av_initialize(struct cx18 *cx)
/* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
/* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */
v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */
v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */
/* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */
cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
/*
* Analog Front End (AFE)
* Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2
* bypass_ch[1-3] use filter
* droop_comp_ch[1-3] disable
* clamp_en_ch[1-3] disable
* aud_in_sel ADC2
* luma_in_sel ADC1
* chroma_in_sel ADC2
* clamp_sel_ch[2-3] midcode
* clamp_sel_ch1 video decoder
* vga_sel_ch3 audio decoder
* vga_sel_ch[1-2] video decoder
* half_bw_ch[1-3] disable
* +12db_ch[1-3] disable
*/
cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00);
/* if(dwEnable && dw3DCombAvailable) { */
/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
@ -195,50 +256,18 @@ static void cx18_av_initialize(struct cx18 *cx)
static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
cx18_av_initialize(cx);
return 0;
}
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
{
struct cx18 *cx = v4l2_get_subdevdata(sd);
/*
* The crystal freq used in calculations in this driver will be
* 28.636360 MHz.
* Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
*/
/*
* VDCLK Integer = 0x0f, Post Divider = 0x04
* AIMCLK Integer = 0x0e, Post Divider = 0x16
*/
cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
/* VDCLK Fraction = 0x2be2fe */
/* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
/* AIMCLK Fraction = 0x05227ad */
/* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
cx18_av_initialize(sd);
return 0;
}
static int cx18_av_load_fw(struct v4l2_subdev *sd)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
if (!state->is_initialized) {
/* initialize on first use */
state->is_initialized = 1;
cx18_av_initialize(cx);
cx18_av_initialize(sd);
}
return 0;
}
@ -248,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx)
struct cx18_av_state *state = &cx->av_state;
struct v4l2_subdev *sd = &state->sd;
v4l2_std_id std = state->std;
/*
* Video ADC crystal clock to pixel clock SRC decimation ratio
* 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
*/
const int src_decimation = 0x21f;
int hblank, hactive, burst, vblank, vactive, sc;
int vblank656, src_decimation;
int vblank656;
int luma_lpf, uv_lpf, comb;
u32 pll_int, pll_frac, pll_post;
@ -259,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx)
else
cx18_av_write(cx, 0x49f, 0x14);
/*
* Note: At the end of a field, there are 3 sets of half line duration
* (double horizontal rate) pulses:
*
* 5 (625) or 6 (525) half-lines to blank for the vertical retrace
* 5 (625) or 6 (525) vertical sync pulses of half line duration
* 5 (625) or 6 (525) half-lines of equalization pulses
*/
if (std & V4L2_STD_625_50) {
/* FIXME - revisit these for Sliced VBI */
/*
* The following relationships of half line counts should hold:
* 625 = vblank656 + vactive
* 10 = vblank656 - vblank = vsync pulses + equalization pulses
*
* vblank656: half lines after line 625/mid-313 of blanked video
* vblank: half lines, after line 5/317, of blanked video
* vactive: half lines of active video +
* 5 half lines after the end of active video
*
* As far as I can tell:
* vblank656 starts counting from the falling edge of the first
* vsync pulse (start of line 1 or mid-313)
* vblank starts counting from the after the 5 vsync pulses and
* 5 or 4 equalization pulses (start of line 6 or 318)
*
* For 625 line systems the driver will extract VBI information
* from lines 6-23 and lines 318-335 (but the slicer can only
* handle 17 lines, not the 18 in the vblank region).
* In addition, we need vblank656 and vblank to be one whole
* line longer, to cover line 24 and 336, so the SAV/EAV RP
* codes get generated such that the encoder can actually
* extract line 23 & 335 (WSS). We'll lose 1 line in each field
* at the top of the screen.
*
* It appears the 5 half lines that happen after active
* video must be included in vactive (579 instead of 574),
* otherwise the colors get badly displayed in various regions
* of the screen. I guess the chroma comb filter gets confused
* without them (at least when a PVR-350 is the PAL source).
*/
vblank656 = 48; /* lines 1 - 24 & 313 - 336 */
vblank = 38; /* lines 6 - 24 & 318 - 336 */
vactive = 579; /* lines 24 - 313 & 337 - 626 */
/*
* For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
* is 864 pixels = 720 active + 144 blanking. ITU-R BT.601
* specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
* the end of active video to start a horizontal line, so that
* leaves 132 pixels of hblank to ignore.
*/
hblank = 132;
hactive = 720;
burst = 93;
vblank = 36;
vactive = 580;
vblank656 = 40;
src_decimation = 0x21f;
/*
* Burst gate delay (for 625 line systems)
* Hsync leading edge to color burst rise = 5.6 us
* Color burst width = 2.25 us
* Gate width = 4 pixel clocks
* (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
*/
burst = 93;
luma_lpf = 2;
if (std & V4L2_STD_PAL) {
uv_lpf = 1;
comb = 0x20;
sc = 688739;
/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
sc = 688700;
} else if (std == V4L2_STD_PAL_Nc) {
uv_lpf = 1;
comb = 0x20;
sc = 556453;
/* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
sc = 556422;
} else { /* SECAM */
uv_lpf = 0;
comb = 0;
sc = 672351;
/* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
/* sc = 4328130 * src_decimation/28636360 * 2^13 */
sc = 672314;
}
} else {
/*
* The following relationships of half line counts should hold:
* 525 = vsync + vactive + vblank656
* 12 = vblank656 - vblank
* 525 = prevsync + vblank656 + vactive
* 12 = vblank656 - vblank = vsync pulses + equalization pulses
*
* vsync: always 6 half-lines of vsync pulses
* vactive: half lines of active video
* prevsync: 6 half-lines before the vsync pulses
* vblank656: half lines, after line 3/mid-266, of blanked video
* vblank: half lines, after line 9/272, of blanked video
* vactive: half lines of active video
*
* As far as I can tell:
* vblank656 starts counting from the falling edge of the first
@ -319,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx)
luma_lpf = 1;
uv_lpf = 1;
src_decimation = 0x21f;
/*
* Burst gate delay (for 525 line systems)
* Hsync leading edge to color burst rise = 5.3 us
* Color burst width = 2.5 us
* Gate width = 4 pixel clocks
* (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
*/
if (std == V4L2_STD_PAL_60) {
burst = 0x5b;
burst = 90;
luma_lpf = 2;
comb = 0x20;
sc = 688739;
/* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
sc = 688700;
} else if (std == V4L2_STD_PAL_M) {
burst = 0x61;
/* The 97 needs to be verified against PAL-M timings */
burst = 97;
comb = 0x20;
sc = 555452;
/* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
sc = 555421;
} else {
burst = 0x5b;
burst = 90;
comb = 0x66;
sc = 556063;
/* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
sc = 556032;
}
}
@ -344,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx)
pll_int, pll_frac, pll_post);
if (pll_post) {
int fin, fsc, pll;
int fsc, pll;
u64 tmp;
pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
pll /= pll_post;
CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
pll / 1000000, pll % 1000000);
CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
pll / 8000000, (pll / 8) % 1000000);
fin = ((u64)src_decimation * pll) >> 12;
CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
fin / 1000000, fin % 1000000);
CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
"= %d.%03d\n", src_decimation / 256,
((src_decimation % 256) * 1000) / 256);
fsc = (((u64)sc) * pll) >> 24L;
tmp = 28636360 * (u64) sc;
do_div(tmp, src_decimation);
fsc = tmp >> 13;
CX18_DEBUG_INFO_DEV(sd,
"Chroma sub-carrier freq = %d.%06d MHz\n",
fsc / 1000000, fsc % 1000000);
"Chroma sub-carrier initial freq = %d.%06d "
"MHz\n", fsc / 1000000, fsc % 1000000);
CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
"vactive %i, vblank656 %i, src_dec %i, "
@ -470,16 +575,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
{
struct cx18_av_state *state = &cx->av_state;
struct v4l2_subdev *sd = &state->sd;
u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
vid_input <= CX18_AV_COMPOSITE8);
u8 reg;
u8 v;
enum analog_signal_type {
NONE, CVBS, Y, C, SIF, Pb, Pr
} ch[3] = {NONE, NONE, NONE};
u8 afe_mux_cfg;
u8 adc2_cfg;
u32 afe_cfg;
int i;
CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
vid_input, aud_input);
if (is_composite) {
reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
if (vid_input >= CX18_AV_COMPOSITE1 &&
vid_input <= CX18_AV_COMPOSITE8) {
afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
ch[0] = CVBS;
} else {
int luma = vid_input & 0xf0;
int chroma = vid_input & 0xf00;
@ -493,26 +605,45 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
vid_input);
return -EINVAL;
}
reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
ch[0] = Y;
if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
reg &= 0x3f;
reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
afe_mux_cfg &= 0x3f;
afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
ch[2] = C;
} else {
reg &= 0xcf;
reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
afe_mux_cfg &= 0xcf;
afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
ch[1] = C;
}
}
/* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */
switch (aud_input) {
case CX18_AV_AUDIO_SERIAL1:
case CX18_AV_AUDIO_SERIAL2:
/* do nothing, use serial audio input */
break;
case CX18_AV_AUDIO4: reg &= ~0x30; break;
case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
case CX18_AV_AUDIO7: reg &= ~0xc0; break;
case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
case CX18_AV_AUDIO4:
afe_mux_cfg &= ~0x30;
ch[1] = SIF;
break;
case CX18_AV_AUDIO5:
afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10;
ch[1] = SIF;
break;
case CX18_AV_AUDIO6:
afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20;
ch[1] = SIF;
break;
case CX18_AV_AUDIO7:
afe_mux_cfg &= ~0xc0;
ch[2] = SIF;
break;
case CX18_AV_AUDIO8:
afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40;
ch[2] = SIF;
break;
default:
CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
@ -520,24 +651,65 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
return -EINVAL;
}
cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
/* Set up analog front end multiplexers */
cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
/* Set INPUT_MODE to Composite (0) or S-Video (1) */
cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02);
/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
v = cx18_av_read(cx, 0x102);
if (reg & 0x80)
v &= ~0x2;
adc2_cfg = cx18_av_read(cx, 0x102);
if (ch[2] == NONE)
adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */
else
v |= 0x2;
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
v |= 0x4;
else
v &= ~0x4;
cx18_av_write_expect(cx, 0x102, v, v, 0x17);
adc2_cfg |= 0x2; /* Signal on CH3, set ADC2 to CH3 for input */
/*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
if (ch[1] != NONE && ch[2] != NONE)
adc2_cfg |= 0x4; /* Set dual mode */
else
adc2_cfg &= ~0x4; /* Clear dual mode */
cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17);
/* Configure the analog front end */
afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL);
afe_cfg &= 0xff000000;
afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */
if (ch[1] != NONE && ch[2] != NONE)
afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */
for (i = 0; i < 3; i++) {
switch (ch[i]) {
default:
case NONE:
/* CLAMP_SEL = Fixed to midcode clamp level */
afe_cfg |= (0x00000200 << i);
break;
case CVBS:
case Y:
if (i > 0)
afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */
break;
case C:
case Pb:
case Pr:
/* CLAMP_SEL = Fixed to midcode clamp level */
afe_cfg |= (0x00000200 << i);
if (i == 0 && ch[i] == C)
afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */
break;
case SIF:
/*
* VGA_GAIN_SEL = Audio Decoder
* CLAMP_SEL = Fixed to midcode clamp level
*/
afe_cfg |= (0x00000240 << i);
if (i == 0)
afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */
break;
}
}
cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg);
state->vid_input = vid_input;
state->aud_input = aud_input;
@ -858,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
* cx18_av_std_setup(), above standard values:
*
* 480 + 1 for 60 Hz systems
* 576 + 4 for 50 Hz systems
* 576 + 3 for 50 Hz systems
*/
Vlines = pix->height + (is_50Hz ? 4 : 1);
Vlines = pix->height + (is_50Hz ? 3 : 1);
/*
* Invalid height and width scaling requests are:

View file

@ -24,15 +24,63 @@
#include "cx18-io.h"
#include <linux/firmware.h>
#define CX18_AUDIO_ENABLE 0xc72014
#define CX18_AUDIO_ENABLE 0xc72014
#define CX18_AI1_MUX_MASK 0x30
#define CX18_AI1_MUX_I2S1 0x00
#define CX18_AI1_MUX_I2S2 0x10
#define CX18_AI1_MUX_843_I2S 0x20
#define CX18_AI1_MUX_INVALID 0x30
#define FWFILE "v4l-cx23418-dig.fw"
static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
{
struct v4l2_subdev *sd = &cx->av_state.sd;
int ret = 0;
const u8 *data;
u32 size;
int addr;
u32 expected, dl_control;
/* Ensure we put the 8051 in reset and enable firmware upload mode */
dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
do {
dl_control &= 0x00ffffff;
dl_control |= 0x0f000000;
cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
} while ((dl_control & 0xff000000) != 0x0f000000);
/* Read and auto increment until at address 0x0000 */
while (dl_control & 0x3fff)
dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
data = fw->data;
size = fw->size;
for (addr = 0; addr < size; addr++) {
dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
if (expected != dl_control) {
CX18_ERR_DEV(sd, "verification of %s firmware load "
"failed: expected %#010x got %#010x\n",
FWFILE, expected, dl_control);
ret = -EIO;
break;
}
dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
}
if (ret == 0)
CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
FWFILE, size);
return ret;
}
int cx18_av_loadfw(struct cx18 *cx)
{
struct v4l2_subdev *sd = &cx->av_state.sd;
const struct firmware *fw = NULL;
u32 size;
u32 v;
u32 u, v;
const u8 *ptr;
int i;
int retries1 = 0;
@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx)
}
cx18_av_write4_expect(cx, CXADEC_DL_CTL,
0x03000000 | fw->size, 0x03000000, 0x13000000);
CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
if (cx18_av_verifyfw(cx, fw) == 0)
cx18_av_write4_expect(cx, CXADEC_DL_CTL,
0x13000000 | fw->size, 0x13000000, 0x13000000);
/* Output to the 416 */
@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx)
cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
0, 0x400);
/* Toggle the AI1 MUX */
v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
u = v & CX18_AI1_MUX_MASK;
v &= ~CX18_AI1_MUX_MASK;
if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
/* Switch to I2S1 */
v |= CX18_AI1_MUX_I2S1;
cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
v, CX18_AI1_MUX_MASK);
/* Switch back to the A/V decoder core I2S output */
v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
} else {
/* Switch to the A/V decoder core I2S output */
v |= CX18_AI1_MUX_843_I2S;
cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
v, CX18_AI1_MUX_MASK);
/* Switch back to I2S1 or I2S2 */
v = (v & ~CX18_AI1_MUX_MASK) | u;
}
cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
v, CX18_AI1_MUX_MASK);
/* Enable WW auto audio standard detection */
v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
v |= 0xFF; /* Auto by default */
@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx)
cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
release_firmware(fw);
CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
return 0;
}

View file

@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
}
cx18_av_write(cx, 0x43c, 0x16);
/* FIXME - should match vblank set in cx18_av_std_setup() */
cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
/* Should match vblank set in cx18_av_std_setup() */
cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
return 0;
}

View file

@ -340,13 +340,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
{ 0, 0, 0 }
};
static const struct cx18_card cx18_card_leadtek_pvr2100 = {
.type = CX18_CARD_LEADTEK_PVR2100,
.name = "Leadtek WinFast PVR2100/DVR3100 H",
.name = "Leadtek WinFast PVR2100",
.comment = "Experimenters and photos needed for device to work well.\n"
"\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
@ -365,15 +364,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
},
.tuners = {
/* XC3028 tuner */
/* XC2028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
.ddr = {
/*
* Pointer to proper DDR config values provided by
* Terry Wu <terrywu at leadtek.com.tw>
*/
/* Pointer to proper DDR config values provided by Terry Wu */
.chip_config = 0x303,
.refresh = 0x3bb,
.timing1 = 0x24220e83,
@ -392,6 +388,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
/* ------------------------------------------------------------------------- */
/* Leadtek WinFast DVR3100 H */
static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
{ PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
{ 0, 0, 0 }
};
static const struct cx18_card cx18_card_leadtek_dvr3100h = {
.type = CX18_CARD_LEADTEK_DVR3100H,
.name = "Leadtek WinFast DVR3100 H",
.comment = "Simultaneous DVB-T and Analog capture supported,\n"
"\texcept when capturing Analog from the antenna input.\n",
.v4l2_capabilities = CX18_CAP_ENCODER,
.hw_audio_ctrl = CX18_HW_418_AV,
.hw_muxer = CX18_HW_GPIO_MUX,
.hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
.video_inputs = {
{ CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
{ CX18_CARD_INPUT_SVIDEO1, 1,
CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
{ CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
},
.audio_inputs = {
{ CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
{ CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
},
.tuners = {
/* XC3028 tuner */
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
.radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
.ddr = {
/* Pointer to proper DDR config values provided by Terry Wu */
.chip_config = 0x303,
.refresh = 0x3bb,
.timing1 = 0x24220e83,
.timing2 = 0x1f,
.tune_lane = 0,
.initial_emrs = 0x2,
},
.gpio_init.initial_value = 0x6,
.gpio_init.direction = 0x7,
.gpio_audio_input = { .mask = 0x7,
.tuner = 0x6, .linein = 0x2, .radio = 0x2 },
.xceive_pin = 1,
.pci_list = cx18_pci_leadtek_dvr3100h,
.i2c = &cx18_i2c_std,
};
/* ------------------------------------------------------------------------- */
static const struct cx18_card *cx18_card_list[] = {
&cx18_card_hvr1600_esmt,
&cx18_card_hvr1600_samsung,
@ -400,6 +448,7 @@ static const struct cx18_card *cx18_card_list[] = {
&cx18_card_cnxt_raptor_pal,
&cx18_card_toshiba_qosmio_dvbt,
&cx18_card_leadtek_pvr2100,
&cx18_card_leadtek_dvr3100h,
};
const struct cx18_card *cx18_get_card(u16 index)

View file

@ -176,8 +176,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
return -EBUSY;
if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
/* We don't do VBI insertion aside from IVTV format in a PS */
!(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
/* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
"the MPEG stream\n");

View file

@ -30,6 +30,7 @@
#include "cx18-irq.h"
#include "cx18-gpio.h"
#include "cx18-firmware.h"
#include "cx18-queue.h"
#include "cx18-streams.h"
#include "cx18-av-core.h"
#include "cx18-scb.h"
@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 4 = Yuan MPC718\n"
"\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
"\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
"\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
"\t\t\t 7 = Leadtek WinFast PVR2100\n"
"\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx)
CX18_INFO("Autodetected %s\n", cx->card_name);
if (tv.tuner_type == TUNER_ABSENT)
CX18_ERR("tveeprom cannot autodetect tuner!");
CX18_ERR("tveeprom cannot autodetect tuner!\n");
if (cx->options.tuner == -1)
cx->options.tuner = tv.tuner_type;
@ -546,6 +548,40 @@ done:
cx->card_i2c = cx->card->i2c;
}
static int __devinit cx18_create_in_workq(struct cx18 *cx)
{
snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
cx->v4l2_dev.name);
cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
if (cx->in_work_queue == NULL) {
CX18_ERR("Unable to create incoming mailbox handler thread\n");
return -ENOMEM;
}
return 0;
}
static int __devinit cx18_create_out_workq(struct cx18 *cx)
{
snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
cx->v4l2_dev.name);
cx->out_work_queue = create_workqueue(cx->out_workq_name);
if (cx->out_work_queue == NULL) {
CX18_ERR("Unable to create outgoing mailbox handler threads\n");
return -ENOMEM;
}
return 0;
}
static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
{
int i;
for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
cx->in_work_order[i].cx = cx;
cx->in_work_order[i].str = cx->epu_debug_str;
INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
}
}
/* Precondition: the cx18 structure has been memset to 0. Only
the dev and instance fields have been filled in.
No assumptions on the card type may be made here (see cx18_init_struct2
@ -553,7 +589,7 @@ done:
*/
static int __devinit cx18_init_struct1(struct cx18 *cx)
{
int i;
int ret;
cx->base_addr = pci_resource_start(cx->pci_dev, 0);
@ -562,17 +598,17 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->epu2apu_mb_lock);
mutex_init(&cx->epu2cpu_mb_lock);
cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
if (cx->work_queue == NULL) {
CX18_ERR("Unable to create work hander thread\n");
return -ENOMEM;
ret = cx18_create_out_workq(cx);
if (ret)
return ret;
ret = cx18_create_in_workq(cx);
if (ret) {
destroy_workqueue(cx->out_work_queue);
return ret;
}
for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
cx->epu_work_order[i].cx = cx;
cx->epu_work_order[i].str = cx->epu_debug_str;
INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler);
}
cx18_init_in_work_orders(cx);
/* start counting open_id at 1 */
cx->open_id = 1;
@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
retval = -ENODEV;
goto err;
}
if (cx18_init_struct1(cx)) {
retval = -ENOMEM;
retval = cx18_init_struct1(cx);
if (retval)
goto err;
}
CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
/* PCI Device Setup */
retval = cx18_setup_pci(cx, pci_dev, pci_id);
if (retval != 0)
goto free_workqueue;
goto free_workqueues;
/* map io memory */
CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@ -943,8 +979,9 @@ free_map:
cx18_iounmap(cx);
free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueue:
destroy_workqueue(cx->work_queue);
free_workqueues:
destroy_workqueue(cx->in_work_queue);
destroy_workqueue(cx->out_work_queue);
err:
if (retval == 0)
retval = -ENODEV;
@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
return 0;
}
static void cx18_cancel_epu_work_orders(struct cx18 *cx)
static void cx18_cancel_in_work_orders(struct cx18 *cx)
{
int i;
for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
cancel_work_sync(&cx->epu_work_order[i].work);
for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
cancel_work_sync(&cx->in_work_order[i].work);
}
static void cx18_cancel_out_work_orders(struct cx18 *cx)
{
int i;
for (i = 0; i < CX18_MAX_STREAMS; i++)
if (&cx->streams[i].video_dev != NULL)
cancel_work_sync(&cx->streams[i].out_work_order);
}
static void cx18_remove(struct pci_dev *pci_dev)
@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev)
if (atomic_read(&cx->tot_capturing) > 0)
cx18_stop_all_captures(cx);
/* Interrupts */
/* Stop interrupts that cause incoming work to be queued */
cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
/* Incoming work can cause outgoing work, so clean up incoming first */
cx18_cancel_in_work_orders(cx);
cx18_cancel_out_work_orders(cx);
/* Stop ack interrupts that may have been needed for work to finish */
cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
cx18_halt_firmware(cx);
cx18_cancel_epu_work_orders(cx);
destroy_workqueue(cx->work_queue);
destroy_workqueue(cx->in_work_queue);
destroy_workqueue(cx->out_work_queue);
cx18_streams_cleanup(cx, 1);

View file

@ -80,8 +80,9 @@
#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */
#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */
#define CX18_CARD_LAST 6
#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */
#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */
#define CX18_CARD_LAST 7
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
@ -254,6 +255,7 @@ struct cx18_options {
#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */
#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */
#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */
/* per-cx18, i_flags */
#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */
@ -285,6 +287,7 @@ struct cx18_queue {
struct list_head list;
atomic_t buffers;
u32 bytesused;
spinlock_t lock;
};
struct cx18_dvb {
@ -305,7 +308,7 @@ struct cx18_scb; /* forward reference */
#define CX18_MAX_MDL_ACKS 2
#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
@ -313,7 +316,7 @@ struct cx18_scb; /* forward reference */
#define CX18_F_EWO_MB_STALE \
(CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
struct cx18_epu_work_order {
struct cx18_in_work_order {
struct work_struct work;
atomic_t pending;
struct cx18 *cx;
@ -337,7 +340,6 @@ struct cx18_stream {
unsigned mdl_offset;
u32 id;
struct mutex qlock; /* locks access to the queues */
unsigned long s_flags; /* status flags, see above */
int dma; /* can be PCI_DMA_TODEVICE,
PCI_DMA_FROMDEVICE or
@ -353,6 +355,8 @@ struct cx18_stream {
struct cx18_queue q_busy; /* busy buffers - in use by firmware */
struct cx18_queue q_full; /* full buffers - data for user apps */
struct work_struct out_work_order;
/* DVB / Digital Transport */
struct cx18_dvb dvb;
};
@ -568,10 +572,14 @@ struct cx18 {
u32 sw2_irq_mask;
u32 hw2_irq_mask;
struct workqueue_struct *work_queue;
struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
struct workqueue_struct *in_work_queue;
char in_workq_name[11]; /* "cx18-NN-in" */
struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
struct workqueue_struct *out_work_queue;
char out_workq_name[12]; /* "cx18-NN-out" */
/* i2c */
struct i2c_adapter i2c_adap[2];
struct i2c_algo_bit_data i2c_algo[2];

Some files were not shown because too many files have changed in this diff Show more