mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-07 13:53:24 +00:00
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:
commit
0dd5198672
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, ®Data);
|
||||
if (result)
|
||||
result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data);
|
||||
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, ®Data);
|
||||
if (result)
|
||||
result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data);
|
||||
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 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
|
||||
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) {
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
|
@ -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 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
|
||||
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 */
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -543,6 +543,7 @@ static int dvb_frontend_thread(void *data)
|
||||
|
||||
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
|
||||
/* got signal or quitting */
|
||||
fepriv->exit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -656,6 +657,7 @@ static int dvb_frontend_thread(void *data)
|
||||
}
|
||||
|
||||
fepriv->thread = NULL;
|
||||
fepriv->exit = 0;
|
||||
mb();
|
||||
|
||||
dvb_frontend_wakeup(fe);
|
||||
|
@ -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.
|
||||
|
@ -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 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
|
||||
/* 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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
}
|
||||
};
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" \
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
308
drivers/media/dvb/frontends/isl6423.c
Normal file
308
drivers/media/dvb/frontends/isl6423.c
Normal 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 = ®, .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");
|
63
drivers/media/dvb/frontends/isl6423.h
Normal file
63
drivers/media/dvb/frontends/isl6423.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -60,8 +60,6 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define dmd_choose(a, b) (demod = STV0900_DEMOD_2 ? b : a))
|
||||
|
||||
static int stvdebug;
|
||||
|
||||
#define dprintk(args...) \
|
||||
|
4299
drivers/media/dvb/frontends/stv090x.c
Normal file
4299
drivers/media/dvb/frontends/stv090x.c
Normal file
File diff suppressed because it is too large
Load Diff
106
drivers/media/dvb/frontends/stv090x.h
Normal file
106
drivers/media/dvb/frontends/stv090x.h
Normal 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 */
|
269
drivers/media/dvb/frontends/stv090x_priv.h
Normal file
269
drivers/media/dvb/frontends/stv090x_priv.h
Normal 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 */
|
2373
drivers/media/dvb/frontends/stv090x_reg.h
Normal file
2373
drivers/media/dvb/frontends/stv090x_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
373
drivers/media/dvb/frontends/stv6110x.c
Normal file
373
drivers/media/dvb/frontends/stv6110x.c
Normal 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");
|
71
drivers/media/dvb/frontends/stv6110x.h
Normal file
71
drivers/media/dvb/frontends/stv6110x.h
Normal 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 */
|
75
drivers/media/dvb/frontends/stv6110x_priv.h
Normal file
75
drivers/media/dvb/frontends/stv6110x_priv.h
Normal 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 */
|
82
drivers/media/dvb/frontends/stv6110x_reg.h
Normal file
82
drivers/media/dvb/frontends/stv6110x_reg.h
Normal 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 */
|
@ -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 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
|
||||
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);
|
||||
|
||||
|
@ -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) || \
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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__ */
|
||||
|
@ -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");
|
||||
|
102
drivers/media/dvb/siano/smsendian.c
Normal file
102
drivers/media/dvb/siano/smsendian.c
Normal 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);
|
32
drivers/media/dvb/siano/smsendian.h
Normal file
32
drivers/media/dvb/siano/smsendian.h
Normal 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__ */
|
||||
|
301
drivers/media/dvb/siano/smsir.c
Normal file
301
drivers/media/dvb/siano/smsir.c
Normal 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("");
|
||||
}
|
||||
|
93
drivers/media/dvb/siano/smsir.h
Normal file
93
drivers/media/dvb/siano/smsir.h
Normal 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__ */
|
||||
|
357
drivers/media/dvb/siano/smssdio.c
Normal file
357
drivers/media/dvb/siano/smssdio.c
Normal 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(¶ms, 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(¶ms, &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");
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) ||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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 @@ static int dsbr100_stop(struct dsbr100_device *radio)
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
|
@ -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>"
|
||||
|
@ -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;
|
||||
|
@ -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")) {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
534
drivers/media/video/adv7343.c
Normal file
534
drivers/media/video/adv7343.c
Normal 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);
|
185
drivers/media/video/adv7343_regs.h
Normal file
185
drivers/media/video/adv7343_regs.h
Normal 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
|
@ -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
|
||||
|
@ -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__);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
@ -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 @@ static void cx18_process_options(struct cx18 *cx)
|
||||
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 @@ static void cx18_process_options(struct cx18 *cx)
|
||||
*/
|
||||
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 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
|
||||
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);
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user