aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/common
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-06-14 15:36:01 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-08-13 22:52:52 -0400
commit0013ca8c52ba7bb1030ed75d6df7e58af0314018 (patch)
tree31672d38162cff3dee895d1d815a8dd85ba67d5d /drivers/media/common
parented0c8b5465d6cec5458d9a3041a5167d83f40fdb (diff)
[media] siano: break it into common, mmc and usb
siano is, in fact, 2 drivers: one for MMC and one for USB, plus a common bus-independent code. Break it accordingly. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/common')
-rw-r--r--drivers/media/common/Kconfig1
-rw-r--r--drivers/media/common/Makefile2
-rw-r--r--drivers/media/common/siano/Kconfig17
-rw-r--r--drivers/media/common/siano/Makefile7
-rw-r--r--drivers/media/common/siano/sms-cards.c311
-rw-r--r--drivers/media/common/siano/sms-cards.h123
-rw-r--r--drivers/media/common/siano/smscoreapi.c1637
-rw-r--r--drivers/media/common/siano/smscoreapi.h775
-rw-r--r--drivers/media/common/siano/smsdvb.c1078
-rw-r--r--drivers/media/common/siano/smsendian.c103
-rw-r--r--drivers/media/common/siano/smsendian.h32
-rw-r--r--drivers/media/common/siano/smsir.c114
-rw-r--r--drivers/media/common/siano/smsir.h55
13 files changed, 4254 insertions, 1 deletions
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 157f191ef646..121b0110af3c 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -1,2 +1,3 @@
1source "drivers/media/common/b2c2/Kconfig" 1source "drivers/media/common/b2c2/Kconfig"
2source "drivers/media/common/saa7146/Kconfig" 2source "drivers/media/common/saa7146/Kconfig"
3source "drivers/media/common/siano/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index f3afd83843e0..b8e2e3a33a31 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1 +1 @@
obj-y += b2c2/ saa7146/ obj-y += b2c2/ saa7146/ siano/
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
new file mode 100644
index 000000000000..425aeadfb49d
--- /dev/null
+++ b/drivers/media/common/siano/Kconfig
@@ -0,0 +1,17 @@
1#
2# Siano Mobile Silicon Digital TV device configuration
3#
4
5config SMS_SIANO_MDTV
6 tristate
7 depends on DVB_CORE && RC_CORE && HAS_DMA
8 depends on SMS_USB_DRV || SMS_SDIO_DRV
9 default y
10 ---help---
11 Choose Y or M here if you have MDTV receiver with a Siano chipset.
12
13 To compile this driver as a module, choose M here
14 (The module will be called smsmdtv).
15
16 Further documentation on this driver can be found on the WWW
17 at http://www.siano-ms.com/
diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile
new file mode 100644
index 000000000000..2a09279e0648
--- /dev/null
+++ b/drivers/media/common/siano/Makefile
@@ -0,0 +1,7 @@
1smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
2
3obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
4
5ccflags-y += -Idrivers/media/dvb-core
6ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
7
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
new file mode 100644
index 000000000000..680c781c8dd6
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.c
@@ -0,0 +1,311 @@
1/*
2 * Card-specific functions for the Siano SMS1xxx USB dongle
3 *
4 * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * Software distributed under the License is distributed on an "AS IS"
11 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
12 *
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#include "sms-cards.h"
21#include "smsir.h"
22#include <linux/module.h>
23
24static int sms_dbg;
25module_param_named(cards_dbg, sms_dbg, int, 0644);
26MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
27
28static struct sms_board sms_boards[] = {
29 [SMS_BOARD_UNKNOWN] = {
30 .name = "Unknown board",
31 },
32 [SMS1XXX_BOARD_SIANO_STELLAR] = {
33 .name = "Siano Stellar Digital Receiver",
34 .type = SMS_STELLAR,
35 },
36 [SMS1XXX_BOARD_SIANO_NOVA_A] = {
37 .name = "Siano Nova A Digital Receiver",
38 .type = SMS_NOVA_A0,
39 },
40 [SMS1XXX_BOARD_SIANO_NOVA_B] = {
41 .name = "Siano Nova B Digital Receiver",
42 .type = SMS_NOVA_B0,
43 },
44 [SMS1XXX_BOARD_SIANO_VEGA] = {
45 .name = "Siano Vega Digital Receiver",
46 .type = SMS_VEGA,
47 },
48 [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
49 .name = "Hauppauge Catamount",
50 .type = SMS_STELLAR,
51 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
52 },
53 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
54 .name = "Hauppauge Okemo-A",
55 .type = SMS_NOVA_A0,
56 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
57 },
58 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
59 .name = "Hauppauge Okemo-B",
60 .type = SMS_NOVA_B0,
61 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
62 },
63 [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
64 .name = "Hauppauge WinTV MiniStick",
65 .type = SMS_NOVA_B0,
66 .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
67 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
68 .rc_codes = RC_MAP_HAUPPAUGE,
69 .board_cfg.leds_power = 26,
70 .board_cfg.led0 = 27,
71 .board_cfg.led1 = 28,
72 .board_cfg.ir = 9,
73 .led_power = 26,
74 .led_lo = 27,
75 .led_hi = 28,
76 },
77 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
78 .name = "Hauppauge WinTV MiniCard",
79 .type = SMS_NOVA_B0,
80 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
81 .lna_ctrl = 29,
82 .board_cfg.foreign_lna0_ctrl = 29,
83 .rf_switch = 17,
84 .board_cfg.rf_switch_uhf = 17,
85 },
86 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
87 .name = "Hauppauge WinTV MiniCard",
88 .type = SMS_NOVA_B0,
89 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
90 .lna_ctrl = -1,
91 },
92 [SMS1XXX_BOARD_SIANO_NICE] = {
93 /* 11 */
94 .name = "Siano Nice Digital Receiver",
95 .type = SMS_NOVA_B0,
96 },
97 [SMS1XXX_BOARD_SIANO_VENICE] = {
98 /* 12 */
99 .name = "Siano Venice Digital Receiver",
100 .type = SMS_VEGA,
101 },
102};
103
104struct sms_board *sms_get_board(unsigned id)
105{
106 BUG_ON(id >= ARRAY_SIZE(sms_boards));
107
108 return &sms_boards[id];
109}
110EXPORT_SYMBOL_GPL(sms_get_board);
111static inline void sms_gpio_assign_11xx_default_led_config(
112 struct smscore_gpio_config *pGpioConfig) {
113 pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
114 pGpioConfig->InputCharacteristics =
115 SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
116 pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
117 pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
118 pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
119}
120
121int sms_board_event(struct smscore_device_t *coredev,
122 enum SMS_BOARD_EVENTS gevent) {
123 struct smscore_gpio_config MyGpioConfig;
124
125 sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
126
127 switch (gevent) {
128 case BOARD_EVENT_POWER_INIT: /* including hotplug */
129 break; /* BOARD_EVENT_BIND */
130
131 case BOARD_EVENT_POWER_SUSPEND:
132 break; /* BOARD_EVENT_POWER_SUSPEND */
133
134 case BOARD_EVENT_POWER_RESUME:
135 break; /* BOARD_EVENT_POWER_RESUME */
136
137 case BOARD_EVENT_BIND:
138 break; /* BOARD_EVENT_BIND */
139
140 case BOARD_EVENT_SCAN_PROG:
141 break; /* BOARD_EVENT_SCAN_PROG */
142 case BOARD_EVENT_SCAN_COMP:
143 break; /* BOARD_EVENT_SCAN_COMP */
144 case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
145 break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
146 case BOARD_EVENT_FE_LOCK:
147 break; /* BOARD_EVENT_FE_LOCK */
148 case BOARD_EVENT_FE_UNLOCK:
149 break; /* BOARD_EVENT_FE_UNLOCK */
150 case BOARD_EVENT_DEMOD_LOCK:
151 break; /* BOARD_EVENT_DEMOD_LOCK */
152 case BOARD_EVENT_DEMOD_UNLOCK:
153 break; /* BOARD_EVENT_DEMOD_UNLOCK */
154 case BOARD_EVENT_RECEPTION_MAX_4:
155 break; /* BOARD_EVENT_RECEPTION_MAX_4 */
156 case BOARD_EVENT_RECEPTION_3:
157 break; /* BOARD_EVENT_RECEPTION_3 */
158 case BOARD_EVENT_RECEPTION_2:
159 break; /* BOARD_EVENT_RECEPTION_2 */
160 case BOARD_EVENT_RECEPTION_1:
161 break; /* BOARD_EVENT_RECEPTION_1 */
162 case BOARD_EVENT_RECEPTION_LOST_0:
163 break; /* BOARD_EVENT_RECEPTION_LOST_0 */
164 case BOARD_EVENT_MULTIPLEX_OK:
165 break; /* BOARD_EVENT_MULTIPLEX_OK */
166 case BOARD_EVENT_MULTIPLEX_ERRORS:
167 break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
168
169 default:
170 sms_err("Unknown SMS board event");
171 break;
172 }
173 return 0;
174}
175EXPORT_SYMBOL_GPL(sms_board_event);
176
177static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
178{
179 int lvl, ret;
180 u32 gpio;
181 struct smscore_config_gpio gpioconfig = {
182 .direction = SMS_GPIO_DIRECTION_OUTPUT,
183 .pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
184 .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
185 .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
186 .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
187 };
188
189 if (pin == 0)
190 return -EINVAL;
191
192 if (pin < 0) {
193 /* inverted gpio */
194 gpio = pin * -1;
195 lvl = enable ? 0 : 1;
196 } else {
197 gpio = pin;
198 lvl = enable ? 1 : 0;
199 }
200
201 ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
202 if (ret < 0)
203 return ret;
204
205 return smscore_set_gpio(coredev, gpio, lvl);
206}
207
208int sms_board_setup(struct smscore_device_t *coredev)
209{
210 int board_id = smscore_get_board_id(coredev);
211 struct sms_board *board = sms_get_board(board_id);
212
213 switch (board_id) {
214 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
215 /* turn off all LEDs */
216 sms_set_gpio(coredev, board->led_power, 0);
217 sms_set_gpio(coredev, board->led_hi, 0);
218 sms_set_gpio(coredev, board->led_lo, 0);
219 break;
220 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
221 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
222 /* turn off LNA */
223 sms_set_gpio(coredev, board->lna_ctrl, 0);
224 break;
225 }
226 return 0;
227}
228EXPORT_SYMBOL_GPL(sms_board_setup);
229
230int sms_board_power(struct smscore_device_t *coredev, int onoff)
231{
232 int board_id = smscore_get_board_id(coredev);
233 struct sms_board *board = sms_get_board(board_id);
234
235 switch (board_id) {
236 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
237 /* power LED */
238 sms_set_gpio(coredev,
239 board->led_power, onoff ? 1 : 0);
240 break;
241 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
242 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
243 /* LNA */
244 if (!onoff)
245 sms_set_gpio(coredev, board->lna_ctrl, 0);
246 break;
247 }
248 return 0;
249}
250EXPORT_SYMBOL_GPL(sms_board_power);
251
252int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
253{
254 int board_id = smscore_get_board_id(coredev);
255 struct sms_board *board = sms_get_board(board_id);
256
257 /* dont touch GPIO if LEDs are already set */
258 if (smscore_led_state(coredev, -1) == led)
259 return 0;
260
261 switch (board_id) {
262 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
263 sms_set_gpio(coredev,
264 board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
265 sms_set_gpio(coredev,
266 board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
267
268 smscore_led_state(coredev, led);
269 break;
270 }
271 return 0;
272}
273EXPORT_SYMBOL_GPL(sms_board_led_feedback);
274
275int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
276{
277 int board_id = smscore_get_board_id(coredev);
278 struct sms_board *board = sms_get_board(board_id);
279
280 sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
281
282 switch (board_id) {
283 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
284 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
285 sms_set_gpio(coredev,
286 board->rf_switch, onoff ? 1 : 0);
287 return sms_set_gpio(coredev,
288 board->lna_ctrl, onoff ? 1 : 0);
289 }
290 return -EINVAL;
291}
292EXPORT_SYMBOL_GPL(sms_board_lna_control);
293
294int sms_board_load_modules(int id)
295{
296 switch (id) {
297 case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
298 case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
299 case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
300 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
301 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
302 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
303 request_module("smsdvb");
304 break;
305 default:
306 /* do nothing */
307 break;
308 }
309 return 0;
310}
311EXPORT_SYMBOL_GPL(sms_board_load_modules);
diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h
new file mode 100644
index 000000000000..d8cdf756f7cf
--- /dev/null
+++ b/drivers/media/common/siano/sms-cards.h
@@ -0,0 +1,123 @@
1/*
2 * Card-specific functions for the Siano SMS1xxx USB dongle
3 *
4 * Copyright (c) 2008 Michael Krufky <mkrufky@linuxtv.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * Software distributed under the License is distributed on an "AS IS"
11 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
12 *
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20#ifndef __SMS_CARDS_H__
21#define __SMS_CARDS_H__
22
23#include <linux/usb.h>
24#include "smscoreapi.h"
25#include "smsir.h"
26
27#define SMS_BOARD_UNKNOWN 0
28#define SMS1XXX_BOARD_SIANO_STELLAR 1
29#define SMS1XXX_BOARD_SIANO_NOVA_A 2
30#define SMS1XXX_BOARD_SIANO_NOVA_B 3
31#define SMS1XXX_BOARD_SIANO_VEGA 4
32#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
33#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
34#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
35#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
36#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
37#define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
38#define SMS1XXX_BOARD_SIANO_NICE 11
39#define SMS1XXX_BOARD_SIANO_VENICE 12
40
41struct sms_board_gpio_cfg {
42 int lna_vhf_exist;
43 int lna_vhf_ctrl;
44 int lna_uhf_exist;
45 int lna_uhf_ctrl;
46 int lna_uhf_d_ctrl;
47 int lna_sband_exist;
48 int lna_sband_ctrl;
49 int lna_sband_d_ctrl;
50 int foreign_lna0_ctrl;
51 int foreign_lna1_ctrl;
52 int foreign_lna2_ctrl;
53 int rf_switch_vhf;
54 int rf_switch_uhf;
55 int rf_switch_sband;
56 int leds_power;
57 int led0;
58 int led1;
59 int led2;
60 int led3;
61 int led4;
62 int ir;
63 int eeprom_wp;
64 int mrc_sense;
65 int mrc_pdn_resetn;
66 int mrc_gp0; /* mrcs spi int */
67 int mrc_gp1;
68 int mrc_gp2;
69 int mrc_gp3;
70 int mrc_gp4;
71 int host_spi_gsp_ts_int;
72};
73
74struct sms_board {
75 enum sms_device_type_st type;
76 char *name, *fw[DEVICE_MODE_MAX];
77 struct sms_board_gpio_cfg board_cfg;
78 char *rc_codes; /* Name of IR codes table */
79
80 /* gpios */
81 int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
82};
83
84struct sms_board *sms_get_board(unsigned id);
85
86extern struct smscore_device_t *coredev;
87
88enum SMS_BOARD_EVENTS {
89 BOARD_EVENT_POWER_INIT,
90 BOARD_EVENT_POWER_SUSPEND,
91 BOARD_EVENT_POWER_RESUME,
92 BOARD_EVENT_BIND,
93 BOARD_EVENT_SCAN_PROG,
94 BOARD_EVENT_SCAN_COMP,
95 BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
96 BOARD_EVENT_FE_LOCK,
97 BOARD_EVENT_FE_UNLOCK,
98 BOARD_EVENT_DEMOD_LOCK,
99 BOARD_EVENT_DEMOD_UNLOCK,
100 BOARD_EVENT_RECEPTION_MAX_4,
101 BOARD_EVENT_RECEPTION_3,
102 BOARD_EVENT_RECEPTION_2,
103 BOARD_EVENT_RECEPTION_1,
104 BOARD_EVENT_RECEPTION_LOST_0,
105 BOARD_EVENT_MULTIPLEX_OK,
106 BOARD_EVENT_MULTIPLEX_ERRORS
107};
108
109int sms_board_event(struct smscore_device_t *coredev,
110 enum SMS_BOARD_EVENTS gevent);
111
112int sms_board_setup(struct smscore_device_t *coredev);
113
114#define SMS_LED_OFF 0
115#define SMS_LED_LO 1
116#define SMS_LED_HI 2
117int sms_board_led_feedback(struct smscore_device_t *coredev, int led);
118int sms_board_power(struct smscore_device_t *coredev, int onoff);
119int sms_board_lna_control(struct smscore_device_t *coredev, int onoff);
120
121extern int sms_board_load_modules(int id);
122
123#endif /* __SMS_CARDS_H__ */
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
new file mode 100644
index 000000000000..9cc55546cc30
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -0,0 +1,1637 @@
1/*
2 * Siano core API module
3 *
4 * This file contains implementation for the interface to sms core component
5 *
6 * author: Uri Shkolnik
7 *
8 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation;
13 *
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
16 *
17 * See the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/dma-mapping.h>
29#include <linux/delay.h>
30#include <linux/io.h>
31#include <linux/slab.h>
32
33#include <linux/firmware.h>
34#include <linux/wait.h>
35#include <asm/byteorder.h>
36
37#include "smscoreapi.h"
38#include "sms-cards.h"
39#include "smsir.h"
40#include "smsendian.h"
41
42static int sms_dbg;
43module_param_named(debug, sms_dbg, int, 0644);
44MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
45
46struct smscore_device_notifyee_t {
47 struct list_head entry;
48 hotplug_t hotplug;
49};
50
51struct smscore_idlist_t {
52 struct list_head entry;
53 int id;
54 int data_type;
55};
56
57struct smscore_client_t {
58 struct list_head entry;
59 struct smscore_device_t *coredev;
60 void *context;
61 struct list_head idlist;
62 onresponse_t onresponse_handler;
63 onremove_t onremove_handler;
64};
65
66void smscore_set_board_id(struct smscore_device_t *core, int id)
67{
68 core->board_id = id;
69}
70
71int smscore_led_state(struct smscore_device_t *core, int led)
72{
73 if (led >= 0)
74 core->led_state = led;
75 return core->led_state;
76}
77EXPORT_SYMBOL_GPL(smscore_set_board_id);
78
79int smscore_get_board_id(struct smscore_device_t *core)
80{
81 return core->board_id;
82}
83EXPORT_SYMBOL_GPL(smscore_get_board_id);
84
85struct smscore_registry_entry_t {
86 struct list_head entry;
87 char devpath[32];
88 int mode;
89 enum sms_device_type_st type;
90};
91
92static struct list_head g_smscore_notifyees;
93static struct list_head g_smscore_devices;
94static struct mutex g_smscore_deviceslock;
95
96static struct list_head g_smscore_registry;
97static struct mutex g_smscore_registrylock;
98
99static int default_mode = 4;
100
101module_param(default_mode, int, 0644);
102MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
103
104static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
105{
106 struct smscore_registry_entry_t *entry;
107 struct list_head *next;
108
109 kmutex_lock(&g_smscore_registrylock);
110 for (next = g_smscore_registry.next;
111 next != &g_smscore_registry;
112 next = next->next) {
113 entry = (struct smscore_registry_entry_t *) next;
114 if (!strcmp(entry->devpath, devpath)) {
115 kmutex_unlock(&g_smscore_registrylock);
116 return entry;
117 }
118 }
119 entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
120 if (entry) {
121 entry->mode = default_mode;
122 strcpy(entry->devpath, devpath);
123 list_add(&entry->entry, &g_smscore_registry);
124 } else
125 sms_err("failed to create smscore_registry.");
126 kmutex_unlock(&g_smscore_registrylock);
127 return entry;
128}
129
130int smscore_registry_getmode(char *devpath)
131{
132 struct smscore_registry_entry_t *entry;
133
134 entry = smscore_find_registry(devpath);
135 if (entry)
136 return entry->mode;
137 else
138 sms_err("No registry found.");
139
140 return default_mode;
141}
142EXPORT_SYMBOL_GPL(smscore_registry_getmode);
143
144static enum sms_device_type_st smscore_registry_gettype(char *devpath)
145{
146 struct smscore_registry_entry_t *entry;
147
148 entry = smscore_find_registry(devpath);
149 if (entry)
150 return entry->type;
151 else
152 sms_err("No registry found.");
153
154 return -1;
155}
156
157void smscore_registry_setmode(char *devpath, int mode)
158{
159 struct smscore_registry_entry_t *entry;
160
161 entry = smscore_find_registry(devpath);
162 if (entry)
163 entry->mode = mode;
164 else
165 sms_err("No registry found.");
166}
167
168static void smscore_registry_settype(char *devpath,
169 enum sms_device_type_st type)
170{
171 struct smscore_registry_entry_t *entry;
172
173 entry = smscore_find_registry(devpath);
174 if (entry)
175 entry->type = type;
176 else
177 sms_err("No registry found.");
178}
179
180
181static void list_add_locked(struct list_head *new, struct list_head *head,
182 spinlock_t *lock)
183{
184 unsigned long flags;
185
186 spin_lock_irqsave(lock, flags);
187
188 list_add(new, head);
189
190 spin_unlock_irqrestore(lock, flags);
191}
192
193/**
194 * register a client callback that called when device plugged in/unplugged
195 * NOTE: if devices exist callback is called immediately for each device
196 *
197 * @param hotplug callback
198 *
199 * @return 0 on success, <0 on error.
200 */
201int smscore_register_hotplug(hotplug_t hotplug)
202{
203 struct smscore_device_notifyee_t *notifyee;
204 struct list_head *next, *first;
205 int rc = 0;
206
207 kmutex_lock(&g_smscore_deviceslock);
208
209 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
210 GFP_KERNEL);
211 if (notifyee) {
212 /* now notify callback about existing devices */
213 first = &g_smscore_devices;
214 for (next = first->next;
215 next != first && !rc;
216 next = next->next) {
217 struct smscore_device_t *coredev =
218 (struct smscore_device_t *) next;
219 rc = hotplug(coredev, coredev->device, 1);
220 }
221
222 if (rc >= 0) {
223 notifyee->hotplug = hotplug;
224 list_add(&notifyee->entry, &g_smscore_notifyees);
225 } else
226 kfree(notifyee);
227 } else
228 rc = -ENOMEM;
229
230 kmutex_unlock(&g_smscore_deviceslock);
231
232 return rc;
233}
234EXPORT_SYMBOL_GPL(smscore_register_hotplug);
235
236/**
237 * unregister a client callback that called when device plugged in/unplugged
238 *
239 * @param hotplug callback
240 *
241 */
242void smscore_unregister_hotplug(hotplug_t hotplug)
243{
244 struct list_head *next, *first;
245
246 kmutex_lock(&g_smscore_deviceslock);
247
248 first = &g_smscore_notifyees;
249
250 for (next = first->next; next != first;) {
251 struct smscore_device_notifyee_t *notifyee =
252 (struct smscore_device_notifyee_t *) next;
253 next = next->next;
254
255 if (notifyee->hotplug == hotplug) {
256 list_del(&notifyee->entry);
257 kfree(notifyee);
258 }
259 }
260
261 kmutex_unlock(&g_smscore_deviceslock);
262}
263EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
264
265static void smscore_notify_clients(struct smscore_device_t *coredev)
266{
267 struct smscore_client_t *client;
268
269 /* the client must call smscore_unregister_client from remove handler */
270 while (!list_empty(&coredev->clients)) {
271 client = (struct smscore_client_t *) coredev->clients.next;
272 client->onremove_handler(client->context);
273 }
274}
275
276static int smscore_notify_callbacks(struct smscore_device_t *coredev,
277 struct device *device, int arrival)
278{
279 struct smscore_device_notifyee_t *elem;
280 int rc = 0;
281
282 /* note: must be called under g_deviceslock */
283
284 list_for_each_entry(elem, &g_smscore_notifyees, entry) {
285 rc = elem->hotplug(coredev, device, arrival);
286 if (rc < 0)
287 break;
288 }
289
290 return rc;
291}
292
293static struct
294smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
295 dma_addr_t common_buffer_phys)
296{
297 struct smscore_buffer_t *cb =
298 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
299 if (!cb) {
300 sms_info("kmalloc(...) failed");
301 return NULL;
302 }
303
304 cb->p = buffer;
305 cb->offset_in_common = buffer - (u8 *) common_buffer;
306 cb->phys = common_buffer_phys + cb->offset_in_common;
307
308 return cb;
309}
310
311/**
312 * creates coredev object for a device, prepares buffers,
313 * creates buffer mappings, notifies registered hotplugs about new device.
314 *
315 * @param params device pointer to struct with device specific parameters
316 * and handlers
317 * @param coredev pointer to a value that receives created coredev object
318 *
319 * @return 0 on success, <0 on error.
320 */
321int smscore_register_device(struct smsdevice_params_t *params,
322 struct smscore_device_t **coredev)
323{
324 struct smscore_device_t *dev;
325 u8 *buffer;
326
327 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
328 if (!dev) {
329 sms_info("kzalloc(...) failed");
330 return -ENOMEM;
331 }
332
333 /* init list entry so it could be safe in smscore_unregister_device */
334 INIT_LIST_HEAD(&dev->entry);
335
336 /* init queues */
337 INIT_LIST_HEAD(&dev->clients);
338 INIT_LIST_HEAD(&dev->buffers);
339
340 /* init locks */
341 spin_lock_init(&dev->clientslock);
342 spin_lock_init(&dev->bufferslock);
343
344 /* init completion events */
345 init_completion(&dev->version_ex_done);
346 init_completion(&dev->data_download_done);
347 init_completion(&dev->trigger_done);
348 init_completion(&dev->init_device_done);
349 init_completion(&dev->reload_start_done);
350 init_completion(&dev->resume_done);
351 init_completion(&dev->gpio_configuration_done);
352 init_completion(&dev->gpio_set_level_done);
353 init_completion(&dev->gpio_get_level_done);
354 init_completion(&dev->ir_init_done);
355
356 /* Buffer management */
357 init_waitqueue_head(&dev->buffer_mng_waitq);
358
359 /* alloc common buffer */
360 dev->common_buffer_size = params->buffer_size * params->num_buffers;
361 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
362 &dev->common_buffer_phys,
363 GFP_KERNEL | GFP_DMA);
364 if (!dev->common_buffer) {
365 smscore_unregister_device(dev);
366 return -ENOMEM;
367 }
368
369 /* prepare dma buffers */
370 for (buffer = dev->common_buffer;
371 dev->num_buffers < params->num_buffers;
372 dev->num_buffers++, buffer += params->buffer_size) {
373 struct smscore_buffer_t *cb =
374 smscore_createbuffer(buffer, dev->common_buffer,
375 dev->common_buffer_phys);
376 if (!cb) {
377 smscore_unregister_device(dev);
378 return -ENOMEM;
379 }
380
381 smscore_putbuffer(dev, cb);
382 }
383
384 sms_info("allocated %d buffers", dev->num_buffers);
385
386 dev->mode = DEVICE_MODE_NONE;
387 dev->context = params->context;
388 dev->device = params->device;
389 dev->setmode_handler = params->setmode_handler;
390 dev->detectmode_handler = params->detectmode_handler;
391 dev->sendrequest_handler = params->sendrequest_handler;
392 dev->preload_handler = params->preload_handler;
393 dev->postload_handler = params->postload_handler;
394
395 dev->device_flags = params->flags;
396 strcpy(dev->devpath, params->devpath);
397
398 smscore_registry_settype(dev->devpath, params->device_type);
399
400 /* add device to devices list */
401 kmutex_lock(&g_smscore_deviceslock);
402 list_add(&dev->entry, &g_smscore_devices);
403 kmutex_unlock(&g_smscore_deviceslock);
404
405 *coredev = dev;
406
407 sms_info("device %p created", dev);
408
409 return 0;
410}
411EXPORT_SYMBOL_GPL(smscore_register_device);
412
413
414static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
415 void *buffer, size_t size, struct completion *completion) {
416 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
417 if (rc < 0) {
418 sms_info("sendrequest returned error %d", rc);
419 return rc;
420 }
421
422 return wait_for_completion_timeout(completion,
423 msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
424 0 : -ETIME;
425}
426
427/**
428 * Starts & enables IR operations
429 *
430 * @return 0 on success, < 0 on error.
431 */
432static int smscore_init_ir(struct smscore_device_t *coredev)
433{
434 int ir_io;
435 int rc;
436 void *buffer;
437
438 coredev->ir.dev = NULL;
439 ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
440 if (ir_io) {/* only if IR port exist we use IR sub-module */
441 sms_info("IR loading");
442 rc = sms_ir_init(coredev);
443
444 if (rc != 0)
445 sms_err("Error initialization DTV IR sub-module");
446 else {
447 buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
448 SMS_DMA_ALIGNMENT,
449 GFP_KERNEL | GFP_DMA);
450 if (buffer) {
451 struct SmsMsgData_ST2 *msg =
452 (struct SmsMsgData_ST2 *)
453 SMS_ALIGN_ADDRESS(buffer);
454
455 SMS_INIT_MSG(&msg->xMsgHeader,
456 MSG_SMS_START_IR_REQ,
457 sizeof(struct SmsMsgData_ST2));
458 msg->msgData[0] = coredev->ir.controller;
459 msg->msgData[1] = coredev->ir.timeout;
460
461 smsendian_handle_tx_message(
462 (struct SmsMsgHdr_ST2 *)msg);
463 rc = smscore_sendrequest_and_wait(coredev, msg,
464 msg->xMsgHeader. msgLength,
465 &coredev->ir_init_done);
466
467 kfree(buffer);
468 } else
469 sms_err
470 ("Sending IR initialization message failed");
471 }
472 } else
473 sms_info("IR port has not been detected");
474
475 return 0;
476}
477
478/**
479 * sets initial device mode and notifies client hotplugs that device is ready
480 *
481 * @param coredev pointer to a coredev object returned by
482 * smscore_register_device
483 *
484 * @return 0 on success, <0 on error.
485 */
486int smscore_start_device(struct smscore_device_t *coredev)
487{
488 int rc = smscore_set_device_mode(
489 coredev, smscore_registry_getmode(coredev->devpath));
490 if (rc < 0) {
491 sms_info("set device mode faile , rc %d", rc);
492 return rc;
493 }
494
495 kmutex_lock(&g_smscore_deviceslock);
496
497 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
498 smscore_init_ir(coredev);
499
500 sms_info("device %p started, rc %d", coredev, rc);
501
502 kmutex_unlock(&g_smscore_deviceslock);
503
504 return rc;
505}
506EXPORT_SYMBOL_GPL(smscore_start_device);
507
508
509static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
510 void *buffer, size_t size)
511{
512 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
513 struct SmsMsgHdr_ST *msg;
514 u32 mem_address;
515 u8 *payload = firmware->Payload;
516 int rc = 0;
517 firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
518 firmware->Length = le32_to_cpu(firmware->Length);
519
520 mem_address = firmware->StartAddress;
521
522 sms_info("loading FW to addr 0x%x size %d",
523 mem_address, firmware->Length);
524 if (coredev->preload_handler) {
525 rc = coredev->preload_handler(coredev->context);
526 if (rc < 0)
527 return rc;
528 }
529
530 /* PAGE_SIZE buffer shall be enough and dma aligned */
531 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
532 if (!msg)
533 return -ENOMEM;
534
535 if (coredev->mode != DEVICE_MODE_NONE) {
536 sms_debug("sending reload command.");
537 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
538 sizeof(struct SmsMsgHdr_ST));
539 rc = smscore_sendrequest_and_wait(coredev, msg,
540 msg->msgLength,
541 &coredev->reload_start_done);
542 mem_address = *(u32 *) &payload[20];
543 }
544
545 while (size && rc >= 0) {
546 struct SmsDataDownload_ST *DataMsg =
547 (struct SmsDataDownload_ST *) msg;
548 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
549
550 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
551 (u16)(sizeof(struct SmsMsgHdr_ST) +
552 sizeof(u32) + payload_size));
553
554 DataMsg->MemAddr = mem_address;
555 memcpy(DataMsg->Payload, payload, payload_size);
556
557 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
558 (coredev->mode == DEVICE_MODE_NONE))
559 rc = coredev->sendrequest_handler(
560 coredev->context, DataMsg,
561 DataMsg->xMsgHeader.msgLength);
562 else
563 rc = smscore_sendrequest_and_wait(
564 coredev, DataMsg,
565 DataMsg->xMsgHeader.msgLength,
566 &coredev->data_download_done);
567
568 payload += payload_size;
569 size -= payload_size;
570 mem_address += payload_size;
571 }
572
573 if (rc >= 0) {
574 if (coredev->mode == DEVICE_MODE_NONE) {
575 struct SmsMsgData_ST *TriggerMsg =
576 (struct SmsMsgData_ST *) msg;
577
578 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
579 sizeof(struct SmsMsgHdr_ST) +
580 sizeof(u32) * 5);
581
582 TriggerMsg->msgData[0] = firmware->StartAddress;
583 /* Entry point */
584 TriggerMsg->msgData[1] = 5; /* Priority */
585 TriggerMsg->msgData[2] = 0x200; /* Stack size */
586 TriggerMsg->msgData[3] = 0; /* Parameter */
587 TriggerMsg->msgData[4] = 4; /* Task ID */
588
589 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
590 rc = coredev->sendrequest_handler(
591 coredev->context, TriggerMsg,
592 TriggerMsg->xMsgHeader.msgLength);
593 msleep(100);
594 } else
595 rc = smscore_sendrequest_and_wait(
596 coredev, TriggerMsg,
597 TriggerMsg->xMsgHeader.msgLength,
598 &coredev->trigger_done);
599 } else {
600 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
601 sizeof(struct SmsMsgHdr_ST));
602
603 rc = coredev->sendrequest_handler(coredev->context,
604 msg, msg->msgLength);
605 }
606 msleep(500);
607 }
608
609 sms_debug("rc=%d, postload=%p ", rc,
610 coredev->postload_handler);
611
612 kfree(msg);
613
614 return ((rc >= 0) && coredev->postload_handler) ?
615 coredev->postload_handler(coredev->context) :
616 rc;
617}
618
619/**
620 * loads specified firmware into a buffer and calls device loadfirmware_handler
621 *
622 * @param coredev pointer to a coredev object returned by
623 * smscore_register_device
624 * @param filename null-terminated string specifies firmware file name
625 * @param loadfirmware_handler device handler that loads firmware
626 *
627 * @return 0 on success, <0 on error.
628 */
629static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
630 char *filename,
631 loadfirmware_t loadfirmware_handler)
632{
633 int rc = -ENOENT;
634 const struct firmware *fw;
635 u8 *fw_buffer;
636
637 if (loadfirmware_handler == NULL && !(coredev->device_flags &
638 SMS_DEVICE_FAMILY2))
639 return -EINVAL;
640
641 rc = request_firmware(&fw, filename, coredev->device);
642 if (rc < 0) {
643 sms_info("failed to open \"%s\"", filename);
644 return rc;
645 }
646 sms_info("read FW %s, size=%zd", filename, fw->size);
647 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
648 GFP_KERNEL | GFP_DMA);
649 if (fw_buffer) {
650 memcpy(fw_buffer, fw->data, fw->size);
651
652 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
653 smscore_load_firmware_family2(coredev,
654 fw_buffer,
655 fw->size) :
656 loadfirmware_handler(coredev->context,
657 fw_buffer, fw->size);
658
659 kfree(fw_buffer);
660 } else {
661 sms_info("failed to allocate firmware buffer");
662 rc = -ENOMEM;
663 }
664
665 release_firmware(fw);
666
667 return rc;
668}
669
670/**
671 * notifies all clients registered with the device, notifies hotplugs,
672 * frees all buffers and coredev object
673 *
674 * @param coredev pointer to a coredev object returned by
675 * smscore_register_device
676 *
677 * @return 0 on success, <0 on error.
678 */
679void smscore_unregister_device(struct smscore_device_t *coredev)
680{
681 struct smscore_buffer_t *cb;
682 int num_buffers = 0;
683 int retry = 0;
684
685 kmutex_lock(&g_smscore_deviceslock);
686
687 /* Release input device (IR) resources */
688 sms_ir_exit(coredev);
689
690 smscore_notify_clients(coredev);
691 smscore_notify_callbacks(coredev, NULL, 0);
692
693 /* at this point all buffers should be back
694 * onresponse must no longer be called */
695
696 while (1) {
697 while (!list_empty(&coredev->buffers)) {
698 cb = (struct smscore_buffer_t *) coredev->buffers.next;
699 list_del(&cb->entry);
700 kfree(cb);
701 num_buffers++;
702 }
703 if (num_buffers == coredev->num_buffers)
704 break;
705 if (++retry > 10) {
706 sms_info("exiting although "
707 "not all buffers released.");
708 break;
709 }
710
711 sms_info("waiting for %d buffer(s)",
712 coredev->num_buffers - num_buffers);
713 msleep(100);
714 }
715
716 sms_info("freed %d buffers", num_buffers);
717
718 if (coredev->common_buffer)
719 dma_free_coherent(NULL, coredev->common_buffer_size,
720 coredev->common_buffer, coredev->common_buffer_phys);
721
722 if (coredev->fw_buf != NULL)
723 kfree(coredev->fw_buf);
724
725 list_del(&coredev->entry);
726 kfree(coredev);
727
728 kmutex_unlock(&g_smscore_deviceslock);
729
730 sms_info("device %p destroyed", coredev);
731}
732EXPORT_SYMBOL_GPL(smscore_unregister_device);
733
734static int smscore_detect_mode(struct smscore_device_t *coredev)
735{
736 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
737 GFP_KERNEL | GFP_DMA);
738 struct SmsMsgHdr_ST *msg =
739 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
740 int rc;
741
742 if (!buffer)
743 return -ENOMEM;
744
745 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
746 sizeof(struct SmsMsgHdr_ST));
747
748 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
749 &coredev->version_ex_done);
750 if (rc == -ETIME) {
751 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
752
753 if (wait_for_completion_timeout(&coredev->resume_done,
754 msecs_to_jiffies(5000))) {
755 rc = smscore_sendrequest_and_wait(
756 coredev, msg, msg->msgLength,
757 &coredev->version_ex_done);
758 if (rc < 0)
759 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
760 "second try, rc %d", rc);
761 } else
762 rc = -ETIME;
763 }
764
765 kfree(buffer);
766
767 return rc;
768}
769
770static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
771 /*Stellar NOVA A0 Nova B0 VEGA*/
772 /*DVBT*/
773 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
774 /*DVBH*/
775 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
776 /*TDMB*/
777 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
778 /*DABIP*/
779 {"none", "none", "none", "none"},
780 /*BDA*/
781 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
782 /*ISDBT*/
783 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
784 /*ISDBTBDA*/
785 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
786 /*CMMB*/
787 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
788};
789
790static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
791 int mode, enum sms_device_type_st type)
792{
793 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
794 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
795}
796
797/**
798 * calls device handler to change mode of operation
799 * NOTE: stellar/usb may disconnect when changing mode
800 *
801 * @param coredev pointer to a coredev object returned by
802 * smscore_register_device
803 * @param mode requested mode of operation
804 *
805 * @return 0 on success, <0 on error.
806 */
807int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
808{
809 void *buffer;
810 int rc = 0;
811 enum sms_device_type_st type;
812
813 sms_debug("set device mode to %d", mode);
814 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
815 if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
816 sms_err("invalid mode specified %d", mode);
817 return -EINVAL;
818 }
819
820 smscore_registry_setmode(coredev->devpath, mode);
821
822 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
823 rc = smscore_detect_mode(coredev);
824 if (rc < 0) {
825 sms_err("mode detect failed %d", rc);
826 return rc;
827 }
828 }
829
830 if (coredev->mode == mode) {
831 sms_info("device mode %d already set", mode);
832 return 0;
833 }
834
835 if (!(coredev->modes_supported & (1 << mode))) {
836 char *fw_filename;
837
838 type = smscore_registry_gettype(coredev->devpath);
839 fw_filename = sms_get_fw_name(coredev, mode, type);
840
841 rc = smscore_load_firmware_from_file(coredev,
842 fw_filename, NULL);
843 if (rc < 0) {
844 sms_warn("error %d loading firmware: %s, "
845 "trying again with default firmware",
846 rc, fw_filename);
847
848 /* try again with the default firmware */
849 fw_filename = smscore_fw_lkup[mode][type];
850 rc = smscore_load_firmware_from_file(coredev,
851 fw_filename, NULL);
852
853 if (rc < 0) {
854 sms_warn("error %d loading "
855 "firmware: %s", rc,
856 fw_filename);
857 return rc;
858 }
859 }
860 sms_log("firmware download success: %s", fw_filename);
861 } else
862 sms_info("mode %d supported by running "
863 "firmware", mode);
864
865 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
866 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
867 if (buffer) {
868 struct SmsMsgData_ST *msg =
869 (struct SmsMsgData_ST *)
870 SMS_ALIGN_ADDRESS(buffer);
871
872 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
873 sizeof(struct SmsMsgData_ST));
874 msg->msgData[0] = mode;
875
876 rc = smscore_sendrequest_and_wait(
877 coredev, msg, msg->xMsgHeader.msgLength,
878 &coredev->init_device_done);
879
880 kfree(buffer);
881 } else {
882 sms_err("Could not allocate buffer for "
883 "init device message.");
884 rc = -ENOMEM;
885 }
886 } else {
887 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
888 sms_err("invalid mode specified %d", mode);
889 return -EINVAL;
890 }
891
892 smscore_registry_setmode(coredev->devpath, mode);
893
894 if (coredev->detectmode_handler)
895 coredev->detectmode_handler(coredev->context,
896 &coredev->mode);
897
898 if (coredev->mode != mode && coredev->setmode_handler)
899 rc = coredev->setmode_handler(coredev->context, mode);
900 }
901
902 if (rc >= 0) {
903 coredev->mode = mode;
904 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
905 }
906
907 if (rc < 0)
908 sms_err("return error code %d.", rc);
909 return rc;
910}
911
912/**
913 * calls device handler to get current mode of operation
914 *
915 * @param coredev pointer to a coredev object returned by
916 * smscore_register_device
917 *
918 * @return current mode
919 */
920int smscore_get_device_mode(struct smscore_device_t *coredev)
921{
922 return coredev->mode;
923}
924EXPORT_SYMBOL_GPL(smscore_get_device_mode);
925
926/**
927 * find client by response id & type within the clients list.
928 * return client handle or NULL.
929 *
930 * @param coredev pointer to a coredev object returned by
931 * smscore_register_device
932 * @param data_type client data type (SMS_DONT_CARE for all types)
933 * @param id client id (SMS_DONT_CARE for all id)
934 *
935 */
936static struct
937smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
938 int data_type, int id)
939{
940 struct list_head *first;
941 struct smscore_client_t *client;
942 unsigned long flags;
943 struct list_head *firstid;
944 struct smscore_idlist_t *client_id;
945
946 spin_lock_irqsave(&coredev->clientslock, flags);
947 first = &coredev->clients;
948 list_for_each_entry(client, first, entry) {
949 firstid = &client->idlist;
950 list_for_each_entry(client_id, firstid, entry) {
951 if ((client_id->id == id) &&
952 (client_id->data_type == data_type ||
953 (client_id->data_type == 0)))
954 goto found;
955 }
956 }
957 client = NULL;
958found:
959 spin_unlock_irqrestore(&coredev->clientslock, flags);
960 return client;
961}
962
963/**
964 * find client by response id/type, call clients onresponse handler
965 * return buffer to pool on error
966 *
967 * @param coredev pointer to a coredev object returned by
968 * smscore_register_device
969 * @param cb pointer to response buffer descriptor
970 *
971 */
972void smscore_onresponse(struct smscore_device_t *coredev,
973 struct smscore_buffer_t *cb) {
974 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
975 + cb->offset);
976 struct smscore_client_t *client;
977 int rc = -EBUSY;
978 static unsigned long last_sample_time; /* = 0; */
979 static int data_total; /* = 0; */
980 unsigned long time_now = jiffies_to_msecs(jiffies);
981
982 if (!last_sample_time)
983 last_sample_time = time_now;
984
985 if (time_now - last_sample_time > 10000) {
986 sms_debug("\ndata rate %d bytes/secs",
987 (int)((data_total * 1000) /
988 (time_now - last_sample_time)));
989
990 last_sample_time = time_now;
991 data_total = 0;
992 }
993
994 data_total += cb->size;
995 /* Do we need to re-route? */
996 if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
997 (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
998 if (coredev->mode == DEVICE_MODE_DVBT_BDA)
999 phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
1000 }
1001
1002
1003 client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1004
1005 /* If no client registered for type & id,
1006 * check for control client where type is not registered */
1007 if (client)
1008 rc = client->onresponse_handler(client->context, cb);
1009
1010 if (rc < 0) {
1011 switch (phdr->msgType) {
1012 case MSG_SMS_GET_VERSION_EX_RES:
1013 {
1014 struct SmsVersionRes_ST *ver =
1015 (struct SmsVersionRes_ST *) phdr;
1016 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1017 "id %d prots 0x%x ver %d.%d",
1018 ver->FirmwareId, ver->SupportedProtocols,
1019 ver->RomVersionMajor, ver->RomVersionMinor);
1020
1021 coredev->mode = ver->FirmwareId == 255 ?
1022 DEVICE_MODE_NONE : ver->FirmwareId;
1023 coredev->modes_supported = ver->SupportedProtocols;
1024
1025 complete(&coredev->version_ex_done);
1026 break;
1027 }
1028 case MSG_SMS_INIT_DEVICE_RES:
1029 sms_debug("MSG_SMS_INIT_DEVICE_RES");
1030 complete(&coredev->init_device_done);
1031 break;
1032 case MSG_SW_RELOAD_START_RES:
1033 sms_debug("MSG_SW_RELOAD_START_RES");
1034 complete(&coredev->reload_start_done);
1035 break;
1036 case MSG_SMS_DATA_DOWNLOAD_RES:
1037 complete(&coredev->data_download_done);
1038 break;
1039 case MSG_SW_RELOAD_EXEC_RES:
1040 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1041 break;
1042 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1043 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1044 complete(&coredev->trigger_done);
1045 break;
1046 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1047 complete(&coredev->resume_done);
1048 break;
1049 case MSG_SMS_GPIO_CONFIG_EX_RES:
1050 sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1051 complete(&coredev->gpio_configuration_done);
1052 break;
1053 case MSG_SMS_GPIO_SET_LEVEL_RES:
1054 sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1055 complete(&coredev->gpio_set_level_done);
1056 break;
1057 case MSG_SMS_GPIO_GET_LEVEL_RES:
1058 {
1059 u32 *msgdata = (u32 *) phdr;
1060 coredev->gpio_get_res = msgdata[1];
1061 sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1062 coredev->gpio_get_res);
1063 complete(&coredev->gpio_get_level_done);
1064 break;
1065 }
1066 case MSG_SMS_START_IR_RES:
1067 complete(&coredev->ir_init_done);
1068 break;
1069 case MSG_SMS_IR_SAMPLES_IND:
1070 sms_ir_event(coredev,
1071 (const char *)
1072 ((char *)phdr
1073 + sizeof(struct SmsMsgHdr_ST)),
1074 (int)phdr->msgLength
1075 - sizeof(struct SmsMsgHdr_ST));
1076 break;
1077
1078 default:
1079 break;
1080 }
1081 smscore_putbuffer(coredev, cb);
1082 }
1083}
1084EXPORT_SYMBOL_GPL(smscore_onresponse);
1085
1086/**
1087 * return pointer to next free buffer descriptor from core pool
1088 *
1089 * @param coredev pointer to a coredev object returned by
1090 * smscore_register_device
1091 *
1092 * @return pointer to descriptor on success, NULL on error.
1093 */
1094
1095struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
1096{
1097 struct smscore_buffer_t *cb = NULL;
1098 unsigned long flags;
1099
1100 spin_lock_irqsave(&coredev->bufferslock, flags);
1101 if (!list_empty(&coredev->buffers)) {
1102 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1103 list_del(&cb->entry);
1104 }
1105 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1106 return cb;
1107}
1108
1109struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1110{
1111 struct smscore_buffer_t *cb = NULL;
1112
1113 wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
1114
1115 return cb;
1116}
1117EXPORT_SYMBOL_GPL(smscore_getbuffer);
1118
1119/**
1120 * return buffer descriptor to a pool
1121 *
1122 * @param coredev pointer to a coredev object returned by
1123 * smscore_register_device
1124 * @param cb pointer buffer descriptor
1125 *
1126 */
1127void smscore_putbuffer(struct smscore_device_t *coredev,
1128 struct smscore_buffer_t *cb) {
1129 wake_up_interruptible(&coredev->buffer_mng_waitq);
1130 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1131}
1132EXPORT_SYMBOL_GPL(smscore_putbuffer);
1133
1134static int smscore_validate_client(struct smscore_device_t *coredev,
1135 struct smscore_client_t *client,
1136 int data_type, int id)
1137{
1138 struct smscore_idlist_t *listentry;
1139 struct smscore_client_t *registered_client;
1140
1141 if (!client) {
1142 sms_err("bad parameter.");
1143 return -EINVAL;
1144 }
1145 registered_client = smscore_find_client(coredev, data_type, id);
1146 if (registered_client == client)
1147 return 0;
1148
1149 if (registered_client) {
1150 sms_err("The msg ID already registered to another client.");
1151 return -EEXIST;
1152 }
1153 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1154 if (!listentry) {
1155 sms_err("Can't allocate memory for client id.");
1156 return -ENOMEM;
1157 }
1158 listentry->id = id;
1159 listentry->data_type = data_type;
1160 list_add_locked(&listentry->entry, &client->idlist,
1161 &coredev->clientslock);
1162 return 0;
1163}
1164
1165/**
1166 * creates smsclient object, check that id is taken by another client
1167 *
1168 * @param coredev pointer to a coredev object from clients hotplug
1169 * @param initial_id all messages with this id would be sent to this client
1170 * @param data_type all messages of this type would be sent to this client
1171 * @param onresponse_handler client handler that is called to
1172 * process incoming messages
1173 * @param onremove_handler client handler that is called when device is removed
1174 * @param context client-specific context
1175 * @param client pointer to a value that receives created smsclient object
1176 *
1177 * @return 0 on success, <0 on error.
1178 */
1179int smscore_register_client(struct smscore_device_t *coredev,
1180 struct smsclient_params_t *params,
1181 struct smscore_client_t **client)
1182{
1183 struct smscore_client_t *newclient;
1184 /* check that no other channel with same parameters exists */
1185 if (smscore_find_client(coredev, params->data_type,
1186 params->initial_id)) {
1187 sms_err("Client already exist.");
1188 return -EEXIST;
1189 }
1190
1191 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1192 if (!newclient) {
1193 sms_err("Failed to allocate memory for client.");
1194 return -ENOMEM;
1195 }
1196
1197 INIT_LIST_HEAD(&newclient->idlist);
1198 newclient->coredev = coredev;
1199 newclient->onresponse_handler = params->onresponse_handler;
1200 newclient->onremove_handler = params->onremove_handler;
1201 newclient->context = params->context;
1202 list_add_locked(&newclient->entry, &coredev->clients,
1203 &coredev->clientslock);
1204 smscore_validate_client(coredev, newclient, params->data_type,
1205 params->initial_id);
1206 *client = newclient;
1207 sms_debug("%p %d %d", params->context, params->data_type,
1208 params->initial_id);
1209
1210 return 0;
1211}
1212EXPORT_SYMBOL_GPL(smscore_register_client);
1213
1214/**
1215 * frees smsclient object and all subclients associated with it
1216 *
1217 * @param client pointer to smsclient object returned by
1218 * smscore_register_client
1219 *
1220 */
1221void smscore_unregister_client(struct smscore_client_t *client)
1222{
1223 struct smscore_device_t *coredev = client->coredev;
1224 unsigned long flags;
1225
1226 spin_lock_irqsave(&coredev->clientslock, flags);
1227
1228
1229 while (!list_empty(&client->idlist)) {
1230 struct smscore_idlist_t *identry =
1231 (struct smscore_idlist_t *) client->idlist.next;
1232 list_del(&identry->entry);
1233 kfree(identry);
1234 }
1235
1236 sms_info("%p", client->context);
1237
1238 list_del(&client->entry);
1239 kfree(client);
1240
1241 spin_unlock_irqrestore(&coredev->clientslock, flags);
1242}
1243EXPORT_SYMBOL_GPL(smscore_unregister_client);
1244
1245/**
1246 * verifies that source id is not taken by another client,
1247 * calls device handler to send requests to the device
1248 *
1249 * @param client pointer to smsclient object returned by
1250 * smscore_register_client
1251 * @param buffer pointer to a request buffer
1252 * @param size size (in bytes) of request buffer
1253 *
1254 * @return 0 on success, <0 on error.
1255 */
1256int smsclient_sendrequest(struct smscore_client_t *client,
1257 void *buffer, size_t size)
1258{
1259 struct smscore_device_t *coredev;
1260 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1261 int rc;
1262
1263 if (client == NULL) {
1264 sms_err("Got NULL client");
1265 return -EINVAL;
1266 }
1267
1268 coredev = client->coredev;
1269
1270 /* check that no other channel with same id exists */
1271 if (coredev == NULL) {
1272 sms_err("Got NULL coredev");
1273 return -EINVAL;
1274 }
1275
1276 rc = smscore_validate_client(client->coredev, client, 0,
1277 phdr->msgSrcId);
1278 if (rc < 0)
1279 return rc;
1280
1281 return coredev->sendrequest_handler(coredev->context, buffer, size);
1282}
1283EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1284
1285
1286/* old GPIO managements implementation */
1287int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1288 struct smscore_config_gpio *pinconfig)
1289{
1290 struct {
1291 struct SmsMsgHdr_ST hdr;
1292 u32 data[6];
1293 } msg;
1294
1295 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1296 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1297 msg.hdr.msgDstId = HIF_TASK;
1298 msg.hdr.msgFlags = 0;
1299 msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1300 msg.hdr.msgLength = sizeof(msg);
1301
1302 msg.data[0] = pin;
1303 msg.data[1] = pinconfig->pullupdown;
1304
1305 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1306 msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1307
1308 switch (pinconfig->outputdriving) {
1309 case SMS_GPIO_OUTPUTDRIVING_16mA:
1310 msg.data[3] = 7; /* Nova - 16mA */
1311 break;
1312 case SMS_GPIO_OUTPUTDRIVING_12mA:
1313 msg.data[3] = 5; /* Nova - 11mA */
1314 break;
1315 case SMS_GPIO_OUTPUTDRIVING_8mA:
1316 msg.data[3] = 3; /* Nova - 7mA */
1317 break;
1318 case SMS_GPIO_OUTPUTDRIVING_4mA:
1319 default:
1320 msg.data[3] = 2; /* Nova - 4mA */
1321 break;
1322 }
1323
1324 msg.data[4] = pinconfig->direction;
1325 msg.data[5] = 0;
1326 } else /* TODO: SMS_DEVICE_FAMILY1 */
1327 return -EINVAL;
1328
1329 return coredev->sendrequest_handler(coredev->context,
1330 &msg, sizeof(msg));
1331}
1332
1333int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1334{
1335 struct {
1336 struct SmsMsgHdr_ST hdr;
1337 u32 data[3];
1338 } msg;
1339
1340 if (pin > MAX_GPIO_PIN_NUMBER)
1341 return -EINVAL;
1342
1343 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1344 msg.hdr.msgDstId = HIF_TASK;
1345 msg.hdr.msgFlags = 0;
1346 msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1347 msg.hdr.msgLength = sizeof(msg);
1348
1349 msg.data[0] = pin;
1350 msg.data[1] = level ? 1 : 0;
1351 msg.data[2] = 0;
1352
1353 return coredev->sendrequest_handler(coredev->context,
1354 &msg, sizeof(msg));
1355}
1356
1357/* new GPIO management implementation */
1358static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1359 u32 *pGroupNum, u32 *pGroupCfg) {
1360
1361 *pGroupCfg = 1;
1362
1363 if (PinNum <= 1) {
1364 *pTranslatedPinNum = 0;
1365 *pGroupNum = 9;
1366 *pGroupCfg = 2;
1367 } else if (PinNum >= 2 && PinNum <= 6) {
1368 *pTranslatedPinNum = 2;
1369 *pGroupNum = 0;
1370 *pGroupCfg = 2;
1371 } else if (PinNum >= 7 && PinNum <= 11) {
1372 *pTranslatedPinNum = 7;
1373 *pGroupNum = 1;
1374 } else if (PinNum >= 12 && PinNum <= 15) {
1375 *pTranslatedPinNum = 12;
1376 *pGroupNum = 2;
1377 *pGroupCfg = 3;
1378 } else if (PinNum == 16) {
1379 *pTranslatedPinNum = 16;
1380 *pGroupNum = 23;
1381 } else if (PinNum >= 17 && PinNum <= 24) {
1382 *pTranslatedPinNum = 17;
1383 *pGroupNum = 3;
1384 } else if (PinNum == 25) {
1385 *pTranslatedPinNum = 25;
1386 *pGroupNum = 6;
1387 } else if (PinNum >= 26 && PinNum <= 28) {
1388 *pTranslatedPinNum = 26;
1389 *pGroupNum = 4;
1390 } else if (PinNum == 29) {
1391 *pTranslatedPinNum = 29;
1392 *pGroupNum = 5;
1393 *pGroupCfg = 2;
1394 } else if (PinNum == 30) {
1395 *pTranslatedPinNum = 30;
1396 *pGroupNum = 8;
1397 } else if (PinNum == 31) {
1398 *pTranslatedPinNum = 31;
1399 *pGroupNum = 17;
1400 } else
1401 return -1;
1402
1403 *pGroupCfg <<= 24;
1404
1405 return 0;
1406}
1407
1408int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1409 struct smscore_gpio_config *pGpioConfig) {
1410
1411 u32 totalLen;
1412 u32 TranslatedPinNum = 0;
1413 u32 GroupNum = 0;
1414 u32 ElectricChar;
1415 u32 groupCfg;
1416 void *buffer;
1417 int rc;
1418
1419 struct SetGpioMsg {
1420 struct SmsMsgHdr_ST xMsgHeader;
1421 u32 msgData[6];
1422 } *pMsg;
1423
1424
1425 if (PinNum > MAX_GPIO_PIN_NUMBER)
1426 return -EINVAL;
1427
1428 if (pGpioConfig == NULL)
1429 return -EINVAL;
1430
1431 totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1432
1433 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1434 GFP_KERNEL | GFP_DMA);
1435 if (!buffer)
1436 return -ENOMEM;
1437
1438 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1439
1440 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1441 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1442 pMsg->xMsgHeader.msgFlags = 0;
1443 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1444 pMsg->msgData[0] = PinNum;
1445
1446 if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1447 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1448 if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
1449 &groupCfg) != 0) {
1450 rc = -EINVAL;
1451 goto free;
1452 }
1453
1454 pMsg->msgData[1] = TranslatedPinNum;
1455 pMsg->msgData[2] = GroupNum;
1456 ElectricChar = (pGpioConfig->PullUpDown)
1457 | (pGpioConfig->InputCharacteristics << 2)
1458 | (pGpioConfig->OutputSlewRate << 3)
1459 | (pGpioConfig->OutputDriving << 4);
1460 pMsg->msgData[3] = ElectricChar;
1461 pMsg->msgData[4] = pGpioConfig->Direction;
1462 pMsg->msgData[5] = groupCfg;
1463 } else {
1464 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1465 pMsg->msgData[1] = pGpioConfig->PullUpDown;
1466 pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
1467 pMsg->msgData[3] = pGpioConfig->OutputDriving;
1468 pMsg->msgData[4] = pGpioConfig->Direction;
1469 pMsg->msgData[5] = 0;
1470 }
1471
1472 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1473 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1474 &coredev->gpio_configuration_done);
1475
1476 if (rc != 0) {
1477 if (rc == -ETIME)
1478 sms_err("smscore_gpio_configure timeout");
1479 else
1480 sms_err("smscore_gpio_configure error");
1481 }
1482free:
1483 kfree(buffer);
1484
1485 return rc;
1486}
1487
1488int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1489 u8 NewLevel) {
1490
1491 u32 totalLen;
1492 int rc;
1493 void *buffer;
1494
1495 struct SetGpioMsg {
1496 struct SmsMsgHdr_ST xMsgHeader;
1497 u32 msgData[3]; /* keep it 3 ! */
1498 } *pMsg;
1499
1500 if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
1501 return -EINVAL;
1502
1503 totalLen = sizeof(struct SmsMsgHdr_ST) +
1504 (3 * sizeof(u32)); /* keep it 3 ! */
1505
1506 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1507 GFP_KERNEL | GFP_DMA);
1508 if (!buffer)
1509 return -ENOMEM;
1510
1511 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1512
1513 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1514 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1515 pMsg->xMsgHeader.msgFlags = 0;
1516 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1517 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1518 pMsg->msgData[0] = PinNum;
1519 pMsg->msgData[1] = NewLevel;
1520
1521 /* Send message to SMS */
1522 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1523 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1524 &coredev->gpio_set_level_done);
1525
1526 if (rc != 0) {
1527 if (rc == -ETIME)
1528 sms_err("smscore_gpio_set_level timeout");
1529 else
1530 sms_err("smscore_gpio_set_level error");
1531 }
1532 kfree(buffer);
1533
1534 return rc;
1535}
1536
1537int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1538 u8 *level) {
1539
1540 u32 totalLen;
1541 int rc;
1542 void *buffer;
1543
1544 struct SetGpioMsg {
1545 struct SmsMsgHdr_ST xMsgHeader;
1546 u32 msgData[2];
1547 } *pMsg;
1548
1549
1550 if (PinNum > MAX_GPIO_PIN_NUMBER)
1551 return -EINVAL;
1552
1553 totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1554
1555 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1556 GFP_KERNEL | GFP_DMA);
1557 if (!buffer)
1558 return -ENOMEM;
1559
1560 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1561
1562 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1563 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1564 pMsg->xMsgHeader.msgFlags = 0;
1565 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
1566 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1567 pMsg->msgData[0] = PinNum;
1568 pMsg->msgData[1] = 0;
1569
1570 /* Send message to SMS */
1571 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1572 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1573 &coredev->gpio_get_level_done);
1574
1575 if (rc != 0) {
1576 if (rc == -ETIME)
1577 sms_err("smscore_gpio_get_level timeout");
1578 else
1579 sms_err("smscore_gpio_get_level error");
1580 }
1581 kfree(buffer);
1582
1583 /* Its a race between other gpio_get_level() and the copy of the single
1584 * global 'coredev->gpio_get_res' to the function's variable 'level'
1585 */
1586 *level = coredev->gpio_get_res;
1587
1588 return rc;
1589}
1590
1591static int __init smscore_module_init(void)
1592{
1593 int rc = 0;
1594
1595 INIT_LIST_HEAD(&g_smscore_notifyees);
1596 INIT_LIST_HEAD(&g_smscore_devices);
1597 kmutex_init(&g_smscore_deviceslock);
1598
1599 INIT_LIST_HEAD(&g_smscore_registry);
1600 kmutex_init(&g_smscore_registrylock);
1601
1602 return rc;
1603}
1604
1605static void __exit smscore_module_exit(void)
1606{
1607 kmutex_lock(&g_smscore_deviceslock);
1608 while (!list_empty(&g_smscore_notifyees)) {
1609 struct smscore_device_notifyee_t *notifyee =
1610 (struct smscore_device_notifyee_t *)
1611 g_smscore_notifyees.next;
1612
1613 list_del(&notifyee->entry);
1614 kfree(notifyee);
1615 }
1616 kmutex_unlock(&g_smscore_deviceslock);
1617
1618 kmutex_lock(&g_smscore_registrylock);
1619 while (!list_empty(&g_smscore_registry)) {
1620 struct smscore_registry_entry_t *entry =
1621 (struct smscore_registry_entry_t *)
1622 g_smscore_registry.next;
1623
1624 list_del(&entry->entry);
1625 kfree(entry);
1626 }
1627 kmutex_unlock(&g_smscore_registrylock);
1628
1629 sms_debug("");
1630}
1631
1632module_init(smscore_module_init);
1633module_exit(smscore_module_exit);
1634
1635MODULE_DESCRIPTION("Siano MDTV Core module");
1636MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1637MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
new file mode 100644
index 000000000000..c592ae090397
--- /dev/null
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -0,0 +1,775 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
21
22#ifndef __SMS_CORE_API_H__
23#define __SMS_CORE_API_H__
24
25#include <linux/device.h>
26#include <linux/list.h>
27#include <linux/mm.h>
28#include <linux/scatterlist.h>
29#include <linux/types.h>
30#include <linux/mutex.h>
31#include <linux/wait.h>
32#include <linux/timer.h>
33
34#include <asm/page.h>
35
36#include "smsir.h"
37
38#define kmutex_init(_p_) mutex_init(_p_)
39#define kmutex_lock(_p_) mutex_lock(_p_)
40#define kmutex_trylock(_p_) mutex_trylock(_p_)
41#define kmutex_unlock(_p_) mutex_unlock(_p_)
42
43#ifndef min
44#define min(a, b) (((a) < (b)) ? (a) : (b))
45#endif
46
47#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000)
48#define SMS_ALLOC_ALIGNMENT 128
49#define SMS_DMA_ALIGNMENT 16
50#define SMS_ALIGN_ADDRESS(addr) \
51 ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
52
53#define SMS_DEVICE_FAMILY2 1
54#define SMS_ROM_NO_RESPONSE 2
55#define SMS_DEVICE_NOT_READY 0x8000000
56
57enum sms_device_type_st {
58 SMS_STELLAR = 0,
59 SMS_NOVA_A0,
60 SMS_NOVA_B0,
61 SMS_VEGA,
62 SMS_NUM_OF_DEVICE_TYPES
63};
64
65struct smscore_device_t;
66struct smscore_client_t;
67struct smscore_buffer_t;
68
69typedef int (*hotplug_t)(struct smscore_device_t *coredev,
70 struct device *device, int arrival);
71
72typedef int (*setmode_t)(void *context, int mode);
73typedef void (*detectmode_t)(void *context, int *mode);
74typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
75typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
76typedef int (*preload_t)(void *context);
77typedef int (*postload_t)(void *context);
78
79typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
80typedef void (*onremove_t)(void *context);
81
82struct smscore_buffer_t {
83 /* public members, once passed to clients can be changed freely */
84 struct list_head entry;
85 int size;
86 int offset;
87
88 /* private members, read-only for clients */
89 void *p;
90 dma_addr_t phys;
91 unsigned long offset_in_common;
92};
93
94struct smsdevice_params_t {
95 struct device *device;
96
97 int buffer_size;
98 int num_buffers;
99
100 char devpath[32];
101 unsigned long flags;
102
103 setmode_t setmode_handler;
104 detectmode_t detectmode_handler;
105 sendrequest_t sendrequest_handler;
106 preload_t preload_handler;
107 postload_t postload_handler;
108
109 void *context;
110 enum sms_device_type_st device_type;
111};
112
113struct smsclient_params_t {
114 int initial_id;
115 int data_type;
116 onresponse_t onresponse_handler;
117 onremove_t onremove_handler;
118 void *context;
119};
120
121struct smscore_device_t {
122 struct list_head entry;
123
124 struct list_head clients;
125 struct list_head subclients;
126 spinlock_t clientslock;
127
128 struct list_head buffers;
129 spinlock_t bufferslock;
130 int num_buffers;
131
132 void *common_buffer;
133 int common_buffer_size;
134 dma_addr_t common_buffer_phys;
135
136 void *context;
137 struct device *device;
138
139 char devpath[32];
140 unsigned long device_flags;
141
142 setmode_t setmode_handler;
143 detectmode_t detectmode_handler;
144 sendrequest_t sendrequest_handler;
145 preload_t preload_handler;
146 postload_t postload_handler;
147
148 int mode, modes_supported;
149
150 /* host <--> device messages */
151 struct completion version_ex_done, data_download_done, trigger_done;
152 struct completion init_device_done, reload_start_done, resume_done;
153 struct completion gpio_configuration_done, gpio_set_level_done;
154 struct completion gpio_get_level_done, ir_init_done;
155
156 /* Buffer management */
157 wait_queue_head_t buffer_mng_waitq;
158
159 /* GPIO */
160 int gpio_get_res;
161
162 /* Target hardware board */
163 int board_id;
164
165 /* Firmware */
166 u8 *fw_buf;
167 u32 fw_buf_size;
168
169 /* Infrared (IR) */
170 struct ir_t ir;
171
172 int led_state;
173};
174
175/* GPIO definitions for antenna frequency domain control (SMS8021) */
176#define SMS_ANTENNA_GPIO_0 1
177#define SMS_ANTENNA_GPIO_1 0
178
179#define BW_8_MHZ 0
180#define BW_7_MHZ 1
181#define BW_6_MHZ 2
182#define BW_5_MHZ 3
183#define BW_ISDBT_1SEG 4
184#define BW_ISDBT_3SEG 5
185
186#define MSG_HDR_FLAG_SPLIT_MSG 4
187
188#define MAX_GPIO_PIN_NUMBER 31
189
190#define HIF_TASK 11
191#define SMS_HOST_LIB 150
192#define DVBT_BDA_CONTROL_MSG_ID 201
193
194#define SMS_MAX_PAYLOAD_SIZE 240
195#define SMS_TUNE_TIMEOUT 500
196
197#define MSG_SMS_GPIO_CONFIG_REQ 507
198#define MSG_SMS_GPIO_CONFIG_RES 508
199#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
200#define MSG_SMS_GPIO_SET_LEVEL_RES 510
201#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
202#define MSG_SMS_GPIO_GET_LEVEL_RES 512
203#define MSG_SMS_RF_TUNE_REQ 561
204#define MSG_SMS_RF_TUNE_RES 562
205#define MSG_SMS_INIT_DEVICE_REQ 578
206#define MSG_SMS_INIT_DEVICE_RES 579
207#define MSG_SMS_ADD_PID_FILTER_REQ 601
208#define MSG_SMS_ADD_PID_FILTER_RES 602
209#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
210#define MSG_SMS_REMOVE_PID_FILTER_RES 604
211#define MSG_SMS_DAB_CHANNEL 607
212#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
213#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
214#define MSG_SMS_GET_STATISTICS_RES 616
215#define MSG_SMS_GET_STATISTICS_REQ 615
216#define MSG_SMS_HO_PER_SLICES_IND 630
217#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
218#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
219#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
220#define MSG_SMS_DATA_DOWNLOAD_REQ 660
221#define MSG_SMS_DATA_DOWNLOAD_RES 661
222#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
223#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
224#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
225#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
226#define MSG_SMS_GET_VERSION_EX_REQ 668
227#define MSG_SMS_GET_VERSION_EX_RES 669
228#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
229#define MSG_SMS_I2C_SET_FREQ_REQ 685
230#define MSG_SMS_GENERIC_I2C_REQ 687
231#define MSG_SMS_GENERIC_I2C_RES 688
232#define MSG_SMS_DVBT_BDA_DATA 693
233#define MSG_SW_RELOAD_REQ 697
234#define MSG_SMS_DATA_MSG 699
235#define MSG_SW_RELOAD_START_REQ 702
236#define MSG_SW_RELOAD_START_RES 703
237#define MSG_SW_RELOAD_EXEC_REQ 704
238#define MSG_SW_RELOAD_EXEC_RES 705
239#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
240#define MSG_SMS_GPIO_CONFIG_EX_REQ 712
241#define MSG_SMS_GPIO_CONFIG_EX_RES 713
242#define MSG_SMS_ISDBT_TUNE_REQ 776
243#define MSG_SMS_ISDBT_TUNE_RES 777
244#define MSG_SMS_TRANSMISSION_IND 782
245#define MSG_SMS_START_IR_REQ 800
246#define MSG_SMS_START_IR_RES 801
247#define MSG_SMS_IR_SAMPLES_IND 802
248#define MSG_SMS_SIGNAL_DETECTED_IND 827
249#define MSG_SMS_NO_SIGNAL_IND 828
250
251#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
252 (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
253 (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
254} while (0)
255
256#define SMS_INIT_MSG(ptr, type, len) \
257 SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
258
259enum SMS_DVB3_EVENTS {
260 DVB3_EVENT_INIT = 0,
261 DVB3_EVENT_SLEEP,
262 DVB3_EVENT_HOTPLUG,
263 DVB3_EVENT_FE_LOCK,
264 DVB3_EVENT_FE_UNLOCK,
265 DVB3_EVENT_UNC_OK,
266 DVB3_EVENT_UNC_ERR
267};
268
269enum SMS_DEVICE_MODE {
270 DEVICE_MODE_NONE = -1,
271 DEVICE_MODE_DVBT = 0,
272 DEVICE_MODE_DVBH,
273 DEVICE_MODE_DAB_TDMB,
274 DEVICE_MODE_DAB_TDMB_DABIP,
275 DEVICE_MODE_DVBT_BDA,
276 DEVICE_MODE_ISDBT,
277 DEVICE_MODE_ISDBT_BDA,
278 DEVICE_MODE_CMMB,
279 DEVICE_MODE_RAW_TUNER,
280 DEVICE_MODE_MAX,
281};
282
283struct SmsMsgHdr_ST {
284 u16 msgType;
285 u8 msgSrcId;
286 u8 msgDstId;
287 u16 msgLength; /* Length of entire message, including header */
288 u16 msgFlags;
289};
290
291struct SmsMsgData_ST {
292 struct SmsMsgHdr_ST xMsgHeader;
293 u32 msgData[1];
294};
295
296struct SmsMsgData_ST2 {
297 struct SmsMsgHdr_ST xMsgHeader;
298 u32 msgData[2];
299};
300
301struct SmsDataDownload_ST {
302 struct SmsMsgHdr_ST xMsgHeader;
303 u32 MemAddr;
304 u8 Payload[SMS_MAX_PAYLOAD_SIZE];
305};
306
307struct SmsVersionRes_ST {
308 struct SmsMsgHdr_ST xMsgHeader;
309
310 u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
311 u8 Step; /* 0 - Step A */
312 u8 MetalFix; /* 0 - Metal 0 */
313
314 /* FirmwareId 0xFF if ROM, otherwise the
315 * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
316 u8 FirmwareId;
317 /* SupportedProtocols Bitwise OR combination of
318 * supported protocols */
319 u8 SupportedProtocols;
320
321 u8 VersionMajor;
322 u8 VersionMinor;
323 u8 VersionPatch;
324 u8 VersionFieldPatch;
325
326 u8 RomVersionMajor;
327 u8 RomVersionMinor;
328 u8 RomVersionPatch;
329 u8 RomVersionFieldPatch;
330
331 u8 TextLabel[34];
332};
333
334struct SmsFirmware_ST {
335 u32 CheckSum;
336 u32 Length;
337 u32 StartAddress;
338 u8 Payload[1];
339};
340
341/* Statistics information returned as response for
342 * SmsHostApiGetStatistics_Req */
343struct SMSHOSTLIB_STATISTICS_ST {
344 u32 Reserved; /* Reserved */
345
346 /* Common parameters */
347 u32 IsRfLocked; /* 0 - not locked, 1 - locked */
348 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
349 u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
350
351 /* Reception quality */
352 s32 SNR; /* dB */
353 u32 BER; /* Post Viterbi BER [1E-5] */
354 u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
355 u32 TS_PER; /* Transport stream PER,
356 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
357 u32 MFER; /* DVB-H frame error rate in percentage,
358 0xFFFFFFFF indicate N/A, valid only for DVB-H */
359 s32 RSSI; /* dBm */
360 s32 InBandPwr; /* In band power in dBM */
361 s32 CarrierOffset; /* Carrier Offset in bin/1024 */
362
363 /* Transmission parameters */
364 u32 Frequency; /* Frequency in Hz */
365 u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */
366 u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
367 for DVB-T/H FFT mode carriers in Kilos */
368 u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
369 valid only for DVB-T/H */
370 u32 GuardInterval; /* Guard Interval from
371 SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */
372 u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
373 valid only for DVB-T/H */
374 u32 LPCodeRate; /* Low Priority Code Rate from
375 SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
376 u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
377 valid only for DVB-T/H */
378 u32 Constellation; /* Constellation from
379 SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
380
381 /* Burst parameters, valid only for DVB-H */
382 u32 BurstSize; /* Current burst size in bytes,
383 valid only for DVB-H */
384 u32 BurstDuration; /* Current burst duration in mSec,
385 valid only for DVB-H */
386 u32 BurstCycleTime; /* Current burst cycle time in mSec,
387 valid only for DVB-H */
388 u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
389 as calculated by demodulator, valid only for DVB-H */
390 u32 NumOfRows; /* Number of rows in MPE table,
391 valid only for DVB-H */
392 u32 NumOfPaddCols; /* Number of padding columns in MPE table,
393 valid only for DVB-H */
394 u32 NumOfPunctCols; /* Number of puncturing columns in MPE table,
395 valid only for DVB-H */
396 u32 ErrorTSPackets; /* Number of erroneous
397 transport-stream packets */
398 u32 TotalTSPackets; /* Total number of transport-stream packets */
399 u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
400 errors after MPE RS decoding */
401 u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
402 after MPE RS decoding */
403 u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
404 corrected by MPE RS decoding */
405 /* Common params */
406 u32 BERErrorCount; /* Number of errornous SYNC bits. */
407 u32 BERBitCount; /* Total number of SYNC bits. */
408
409 /* Interface information */
410 u32 SmsToHostTxErrors; /* Total number of transmission errors. */
411
412 /* DAB/T-DMB */
413 u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
414
415 /* DVB-H TPS parameters */
416 u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
417 if set to 0xFFFFFFFF cell_id not yet recovered */
418 u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
419 Time Slicing indicator, bit 0 - MPE-FEC indicator */
420 u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
421 Time Slicing indicator, bit 0 - MPE-FEC indicator */
422
423 u32 NumMPEReceived; /* DVB-H, Num MPE section received */
424
425 u32 ReservedFields[10]; /* Reserved */
426};
427
428struct SmsMsgStatisticsInfo_ST {
429 u32 RequestResult;
430
431 struct SMSHOSTLIB_STATISTICS_ST Stat;
432
433 /* Split the calc of the SNR in DAB */
434 u32 Signal; /* dB */
435 u32 Noise; /* dB */
436
437};
438
439struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST {
440 /* Per-layer information */
441 u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
442 * 255 means layer does not exist */
443 u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET,
444 * 255 means layer does not exist */
445 u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
446 u32 BERErrorCount; /* Post Viterbi Error Bits Count */
447 u32 BERBitCount; /* Post Viterbi Total Bits Count */
448 u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */
449 u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */
450 u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
451 u32 TotalTSPackets; /* Total number of transport-stream packets */
452 u32 TILdepthI; /* Time interleaver depth I parameter,
453 * 255 means layer does not exist */
454 u32 NumberOfSegments; /* Number of segments in layer A,
455 * 255 means layer does not exist */
456 u32 TMCCErrors; /* TMCC errors */
457};
458
459struct SMSHOSTLIB_STATISTICS_ISDBT_ST {
460 u32 StatisticsType; /* Enumerator identifying the type of the
461 * structure. Values are the same as
462 * SMSHOSTLIB_DEVICE_MODES_E
463 *
464 * This field MUST always be first in any
465 * statistics structure */
466
467 u32 FullSize; /* Total size of the structure returned by the modem.
468 * If the size requested by the host is smaller than
469 * FullSize, the struct will be truncated */
470
471 /* Common parameters */
472 u32 IsRfLocked; /* 0 - not locked, 1 - locked */
473 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
474 u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
475
476 /* Reception quality */
477 s32 SNR; /* dB */
478 s32 RSSI; /* dBm */
479 s32 InBandPwr; /* In band power in dBM */
480 s32 CarrierOffset; /* Carrier Offset in Hz */
481
482 /* Transmission parameters */
483 u32 Frequency; /* Frequency in Hz */
484 u32 Bandwidth; /* Bandwidth in MHz */
485 u32 TransmissionMode; /* ISDB-T transmission mode */
486 u32 ModemState; /* 0 - Acquisition, 1 - Locked */
487 u32 GuardInterval; /* Guard Interval, 1 divided by value */
488 u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */
489 u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */
490 u32 NumOfLayers; /* Number of ISDB-T layers in the network */
491
492 /* Per-layer information */
493 /* Layers A, B and C */
494 struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3];
495 /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */
496
497 /* Interface information */
498 u32 SmsToHostTxErrors; /* Total number of transmission errors. */
499};
500
501struct PID_STATISTICS_DATA_S {
502 struct PID_BURST_S {
503 u32 size;
504 u32 padding_cols;
505 u32 punct_cols;
506 u32 duration;
507 u32 cycle;
508 u32 calc_cycle;
509 } burst;
510
511 u32 tot_tbl_cnt;
512 u32 invalid_tbl_cnt;
513 u32 tot_cor_tbl;
514};
515
516struct PID_DATA_S {
517 u32 pid;
518 u32 num_rows;
519 struct PID_STATISTICS_DATA_S pid_statistics;
520};
521
522#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
523#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
524#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
525 if (_stat.TransmissionMode == 0) \
526 _stat.TransmissionMode = 2; \
527 else if (_stat.TransmissionMode == 1) \
528 _stat.TransmissionMode = 8; \
529 else \
530 _stat.TransmissionMode = 4;
531
532struct TRANSMISSION_STATISTICS_S {
533 u32 Frequency; /* Frequency in Hz */
534 u32 Bandwidth; /* Bandwidth in MHz */
535 u32 TransmissionMode; /* FFT mode carriers in Kilos */
536 u32 GuardInterval; /* Guard Interval from
537 SMSHOSTLIB_GUARD_INTERVALS_ET */
538 u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
539 u32 LPCodeRate; /* Low Priority Code Rate from
540 SMSHOSTLIB_CODE_RATE_ET */
541 u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
542 u32 Constellation; /* Constellation from
543 SMSHOSTLIB_CONSTELLATION_ET */
544
545 /* DVB-H TPS parameters */
546 u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
547 if set to 0xFFFFFFFF cell_id not yet recovered */
548 u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 -
549 Time Slicing indicator, bit 0 - MPE-FEC indicator */
550 u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 -
551 Time Slicing indicator, bit 0 - MPE-FEC indicator */
552 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
553};
554
555struct RECEPTION_STATISTICS_S {
556 u32 IsRfLocked; /* 0 - not locked, 1 - locked */
557 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
558 u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
559
560 u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
561 s32 SNR; /* dB */
562 u32 BER; /* Post Viterbi BER [1E-5] */
563 u32 BERErrorCount; /* Number of erronous SYNC bits. */
564 u32 BERBitCount; /* Total number of SYNC bits. */
565 u32 TS_PER; /* Transport stream PER,
566 0xFFFFFFFF indicate N/A */
567 u32 MFER; /* DVB-H frame error rate in percentage,
568 0xFFFFFFFF indicate N/A, valid only for DVB-H */
569 s32 RSSI; /* dBm */
570 s32 InBandPwr; /* In band power in dBM */
571 s32 CarrierOffset; /* Carrier Offset in bin/1024 */
572 u32 ErrorTSPackets; /* Number of erroneous
573 transport-stream packets */
574 u32 TotalTSPackets; /* Total number of transport-stream packets */
575
576 s32 MRC_SNR; /* dB */
577 s32 MRC_RSSI; /* dBm */
578 s32 MRC_InBandPwr; /* In band power in dBM */
579};
580
581
582/* Statistics information returned as response for
583 * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
584struct SMSHOSTLIB_STATISTICS_DVB_S {
585 /* Reception */
586 struct RECEPTION_STATISTICS_S ReceptionData;
587
588 /* Transmission parameters */
589 struct TRANSMISSION_STATISTICS_S TransmissionData;
590
591 /* Burst parameters, valid only for DVB-H */
592#define SRVM_MAX_PID_FILTERS 8
593 struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
594};
595
596struct SRVM_SIGNAL_STATUS_S {
597 u32 result;
598 u32 snr;
599 u32 tsPackets;
600 u32 etsPackets;
601 u32 constellation;
602 u32 hpCode;
603 u32 tpsSrvIndLP;
604 u32 tpsSrvIndHP;
605 u32 cellId;
606 u32 reason;
607
608 s32 inBandPower;
609 u32 requestId;
610};
611
612struct SMSHOSTLIB_I2C_REQ_ST {
613 u32 DeviceAddress; /* I2c device address */
614 u32 WriteCount; /* number of bytes to write */
615 u32 ReadCount; /* number of bytes to read */
616 u8 Data[1];
617};
618
619struct SMSHOSTLIB_I2C_RES_ST {
620 u32 Status; /* non-zero value in case of failure */
621 u32 ReadCount; /* number of bytes read */
622 u8 Data[1];
623};
624
625
626struct smscore_config_gpio {
627#define SMS_GPIO_DIRECTION_INPUT 0
628#define SMS_GPIO_DIRECTION_OUTPUT 1
629 u8 direction;
630
631#define SMS_GPIO_PULLUPDOWN_NONE 0
632#define SMS_GPIO_PULLUPDOWN_PULLDOWN 1
633#define SMS_GPIO_PULLUPDOWN_PULLUP 2
634#define SMS_GPIO_PULLUPDOWN_KEEPER 3
635 u8 pullupdown;
636
637#define SMS_GPIO_INPUTCHARACTERISTICS_NORMAL 0
638#define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1
639 u8 inputcharacteristics;
640
641#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0
642#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1
643 u8 outputslewrate;
644
645#define SMS_GPIO_OUTPUTDRIVING_4mA 0
646#define SMS_GPIO_OUTPUTDRIVING_8mA 1
647#define SMS_GPIO_OUTPUTDRIVING_12mA 2
648#define SMS_GPIO_OUTPUTDRIVING_16mA 3
649 u8 outputdriving;
650};
651
652struct smscore_gpio_config {
653#define SMS_GPIO_DIRECTION_INPUT 0
654#define SMS_GPIO_DIRECTION_OUTPUT 1
655 u8 Direction;
656
657#define SMS_GPIO_PULL_UP_DOWN_NONE 0
658#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
659#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2
660#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3
661 u8 PullUpDown;
662
663#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0
664#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
665 u8 InputCharacteristics;
666
667#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */
668#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */
669
670
671#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */
672#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */
673#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */
674#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */
675 u8 OutputSlewRate;
676
677#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */
678#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */
679#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */
680#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */
681
682#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */
683#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */
684#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */
685#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */
686#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */
687#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */
688#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */
689#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */
690 u8 OutputDriving;
691};
692
693extern void smscore_registry_setmode(char *devpath, int mode);
694extern int smscore_registry_getmode(char *devpath);
695
696extern int smscore_register_hotplug(hotplug_t hotplug);
697extern void smscore_unregister_hotplug(hotplug_t hotplug);
698
699extern int smscore_register_device(struct smsdevice_params_t *params,
700 struct smscore_device_t **coredev);
701extern void smscore_unregister_device(struct smscore_device_t *coredev);
702
703extern int smscore_start_device(struct smscore_device_t *coredev);
704extern int smscore_load_firmware(struct smscore_device_t *coredev,
705 char *filename,
706 loadfirmware_t loadfirmware_handler);
707
708extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
709extern int smscore_get_device_mode(struct smscore_device_t *coredev);
710
711extern int smscore_register_client(struct smscore_device_t *coredev,
712 struct smsclient_params_t *params,
713 struct smscore_client_t **client);
714extern void smscore_unregister_client(struct smscore_client_t *client);
715
716extern int smsclient_sendrequest(struct smscore_client_t *client,
717 void *buffer, size_t size);
718extern void smscore_onresponse(struct smscore_device_t *coredev,
719 struct smscore_buffer_t *cb);
720
721extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev);
722extern int smscore_map_common_buffer(struct smscore_device_t *coredev,
723 struct vm_area_struct *vma);
724extern int smscore_get_fw_filename(struct smscore_device_t *coredev,
725 int mode, char *filename);
726extern int smscore_send_fw_file(struct smscore_device_t *coredev,
727 u8 *ufwbuf, int size);
728
729extern
730struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
731extern void smscore_putbuffer(struct smscore_device_t *coredev,
732 struct smscore_buffer_t *cb);
733
734/* old GPIO management */
735int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
736 struct smscore_config_gpio *pinconfig);
737int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
738
739/* new GPIO management */
740extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
741 struct smscore_gpio_config *pGpioConfig);
742extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
743 u8 NewLevel);
744extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
745 u8 *level);
746
747void smscore_set_board_id(struct smscore_device_t *core, int id);
748int smscore_get_board_id(struct smscore_device_t *core);
749
750int smscore_led_state(struct smscore_device_t *core, int led);
751
752
753/* ------------------------------------------------------------------------ */
754
755#define DBG_INFO 1
756#define DBG_ADV 2
757
758#define sms_printk(kern, fmt, arg...) \
759 printk(kern "%s: " fmt "\n", __func__, ##arg)
760
761#define dprintk(kern, lvl, fmt, arg...) do {\
762 if (sms_dbg & lvl) \
763 sms_printk(kern, fmt, ##arg); } while (0)
764
765#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
766#define sms_err(fmt, arg...) \
767 sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
768#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
769#define sms_info(fmt, arg...) \
770 dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
771#define sms_debug(fmt, arg...) \
772 dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
773
774
775#endif /* __SMS_CORE_API_H__ */
diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c
new file mode 100644
index 000000000000..aa77e54a8fae
--- /dev/null
+++ b/drivers/media/common/siano/smsdvb.c
@@ -0,0 +1,1078 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
21
22#include <linux/module.h>
23#include <linux/slab.h>
24#include <linux/init.h>
25
26#include "dmxdev.h"
27#include "dvbdev.h"
28#include "dvb_demux.h"
29#include "dvb_frontend.h"
30
31#include "smscoreapi.h"
32#include "smsendian.h"
33#include "sms-cards.h"
34
35DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36
37struct smsdvb_client_t {
38 struct list_head entry;
39
40 struct smscore_device_t *coredev;
41 struct smscore_client_t *smsclient;
42
43 struct dvb_adapter adapter;
44 struct dvb_demux demux;
45 struct dmxdev dmxdev;
46 struct dvb_frontend frontend;
47
48 fe_status_t fe_status;
49
50 struct completion tune_done;
51
52 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
53 int event_fe_state;
54 int event_unc_state;
55};
56
57static struct list_head g_smsdvb_clients;
58static struct mutex g_smsdvb_clientslock;
59
60static int sms_dbg;
61module_param_named(debug, sms_dbg, int, 0644);
62MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
63
64/* Events that may come from DVB v3 adapter */
65static void sms_board_dvb3_event(struct smsdvb_client_t *client,
66 enum SMS_DVB3_EVENTS event) {
67
68 struct smscore_device_t *coredev = client->coredev;
69 switch (event) {
70 case DVB3_EVENT_INIT:
71 sms_debug("DVB3_EVENT_INIT");
72 sms_board_event(coredev, BOARD_EVENT_BIND);
73 break;
74 case DVB3_EVENT_SLEEP:
75 sms_debug("DVB3_EVENT_SLEEP");
76 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
77 break;
78 case DVB3_EVENT_HOTPLUG:
79 sms_debug("DVB3_EVENT_HOTPLUG");
80 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
81 break;
82 case DVB3_EVENT_FE_LOCK:
83 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
84 client->event_fe_state = DVB3_EVENT_FE_LOCK;
85 sms_debug("DVB3_EVENT_FE_LOCK");
86 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
87 }
88 break;
89 case DVB3_EVENT_FE_UNLOCK:
90 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
91 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
92 sms_debug("DVB3_EVENT_FE_UNLOCK");
93 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
94 }
95 break;
96 case DVB3_EVENT_UNC_OK:
97 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
98 client->event_unc_state = DVB3_EVENT_UNC_OK;
99 sms_debug("DVB3_EVENT_UNC_OK");
100 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
101 }
102 break;
103 case DVB3_EVENT_UNC_ERR:
104 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
105 client->event_unc_state = DVB3_EVENT_UNC_ERR;
106 sms_debug("DVB3_EVENT_UNC_ERR");
107 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
108 }
109 break;
110
111 default:
112 sms_err("Unknown dvb3 api event");
113 break;
114 }
115}
116
117
118static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
119 struct SMSHOSTLIB_STATISTICS_ST *p)
120{
121 if (sms_dbg & 2) {
122 printk(KERN_DEBUG "Reserved = %d", p->Reserved);
123 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
124 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
125 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
126 printk(KERN_DEBUG "SNR = %d", p->SNR);
127 printk(KERN_DEBUG "BER = %d", p->BER);
128 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
129 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
130 printk(KERN_DEBUG "MFER = %d", p->MFER);
131 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
132 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
133 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
134 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
135 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
136 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
137 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
138 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
139 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
140 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
141 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
142 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
143 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
144 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
145 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
146 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
147 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
148 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
149 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
150 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
151 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
152 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
153 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
154 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
155 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
156 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
157 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
158 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
159 printk(KERN_DEBUG "CellId = %d", p->CellId);
160 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
161 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
162 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
163 }
164
165 pReceptionData->IsDemodLocked = p->IsDemodLocked;
166
167 pReceptionData->SNR = p->SNR;
168 pReceptionData->BER = p->BER;
169 pReceptionData->BERErrorCount = p->BERErrorCount;
170 pReceptionData->InBandPwr = p->InBandPwr;
171 pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
172};
173
174
175static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
176 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
177{
178 int i;
179
180 if (sms_dbg & 2) {
181 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
182 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
183 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
184 printk(KERN_DEBUG "SNR = %d", p->SNR);
185 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
186 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
187 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
188 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
189 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
190 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
191 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
192 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
193 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
194 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
195 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
196 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
197
198 for (i = 0; i < 3; i++) {
199 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
200 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
201 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
202 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
203 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
204 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
205 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
206 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
207 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
208 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
209 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
210 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
211 }
212 }
213
214 pReceptionData->IsDemodLocked = p->IsDemodLocked;
215
216 pReceptionData->SNR = p->SNR;
217 pReceptionData->InBandPwr = p->InBandPwr;
218
219 pReceptionData->ErrorTSPackets = 0;
220 pReceptionData->BER = 0;
221 pReceptionData->BERErrorCount = 0;
222 for (i = 0; i < 3; i++) {
223 pReceptionData->BER += p->LayerInfo[i].BER;
224 pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
225 pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
226 }
227}
228
229static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
230{
231 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
232 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
233 + cb->offset);
234 u32 *pMsgData = (u32 *) phdr + 1;
235 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
236 bool is_status_update = false;
237
238 smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
239
240 switch (phdr->msgType) {
241 case MSG_SMS_DVBT_BDA_DATA:
242 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
243 cb->size - sizeof(struct SmsMsgHdr_ST));
244 break;
245
246 case MSG_SMS_RF_TUNE_RES:
247 case MSG_SMS_ISDBT_TUNE_RES:
248 complete(&client->tune_done);
249 break;
250
251 case MSG_SMS_SIGNAL_DETECTED_IND:
252 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
253 client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
254 is_status_update = true;
255 break;
256
257 case MSG_SMS_NO_SIGNAL_IND:
258 sms_info("MSG_SMS_NO_SIGNAL_IND");
259 client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
260 is_status_update = true;
261 break;
262
263 case MSG_SMS_TRANSMISSION_IND: {
264 sms_info("MSG_SMS_TRANSMISSION_IND");
265
266 pMsgData++;
267 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
268 sizeof(struct TRANSMISSION_STATISTICS_S));
269
270 /* Mo need to correct guard interval
271 * (as opposed to old statistics message).
272 */
273 CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
274 CORRECT_STAT_TRANSMISSON_MODE(
275 client->sms_stat_dvb.TransmissionData);
276 is_status_update = true;
277 break;
278 }
279 case MSG_SMS_HO_PER_SLICES_IND: {
280 struct RECEPTION_STATISTICS_S *pReceptionData =
281 &client->sms_stat_dvb.ReceptionData;
282 struct SRVM_SIGNAL_STATUS_S SignalStatusData;
283
284 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
285 pMsgData++;
286 SignalStatusData.result = pMsgData[0];
287 SignalStatusData.snr = pMsgData[1];
288 SignalStatusData.inBandPower = (s32) pMsgData[2];
289 SignalStatusData.tsPackets = pMsgData[3];
290 SignalStatusData.etsPackets = pMsgData[4];
291 SignalStatusData.constellation = pMsgData[5];
292 SignalStatusData.hpCode = pMsgData[6];
293 SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
294 SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
295 SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
296 SignalStatusData.reason = pMsgData[10];
297 SignalStatusData.requestId = pMsgData[11];
298 pReceptionData->IsRfLocked = pMsgData[16];
299 pReceptionData->IsDemodLocked = pMsgData[17];
300 pReceptionData->ModemState = pMsgData[12];
301 pReceptionData->SNR = pMsgData[1];
302 pReceptionData->BER = pMsgData[13];
303 pReceptionData->RSSI = pMsgData[14];
304 CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
305
306 pReceptionData->InBandPwr = (s32) pMsgData[2];
307 pReceptionData->CarrierOffset = (s32) pMsgData[15];
308 pReceptionData->TotalTSPackets = pMsgData[3];
309 pReceptionData->ErrorTSPackets = pMsgData[4];
310
311 /* TS PER */
312 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
313 > 0) {
314 pReceptionData->TS_PER = (SignalStatusData.etsPackets
315 * 100) / (SignalStatusData.tsPackets
316 + SignalStatusData.etsPackets);
317 } else {
318 pReceptionData->TS_PER = 0;
319 }
320
321 pReceptionData->BERBitCount = pMsgData[18];
322 pReceptionData->BERErrorCount = pMsgData[19];
323
324 pReceptionData->MRC_SNR = pMsgData[20];
325 pReceptionData->MRC_InBandPwr = pMsgData[21];
326 pReceptionData->MRC_RSSI = pMsgData[22];
327
328 is_status_update = true;
329 break;
330 }
331 case MSG_SMS_GET_STATISTICS_RES: {
332 union {
333 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
334 struct SmsMsgStatisticsInfo_ST dvb;
335 } *p = (void *) (phdr + 1);
336 struct RECEPTION_STATISTICS_S *pReceptionData =
337 &client->sms_stat_dvb.ReceptionData;
338
339 sms_info("MSG_SMS_GET_STATISTICS_RES");
340
341 is_status_update = true;
342
343 switch (smscore_get_device_mode(client->coredev)) {
344 case DEVICE_MODE_ISDBT:
345 case DEVICE_MODE_ISDBT_BDA:
346 smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
347 break;
348 default:
349 smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
350 }
351 if (!pReceptionData->IsDemodLocked) {
352 pReceptionData->SNR = 0;
353 pReceptionData->BER = 0;
354 pReceptionData->BERErrorCount = 0;
355 pReceptionData->InBandPwr = 0;
356 pReceptionData->ErrorTSPackets = 0;
357 }
358
359 complete(&client->tune_done);
360 break;
361 }
362 default:
363 sms_info("Unhandled message %d", phdr->msgType);
364
365 }
366 smscore_putbuffer(client->coredev, cb);
367
368 if (is_status_update) {
369 if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
370 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
371 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
372 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
373 if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
374 == 0)
375 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
376 else
377 sms_board_dvb3_event(client,
378 DVB3_EVENT_UNC_ERR);
379
380 } else {
381 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
382 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
383 else
384 client->fe_status = 0;
385 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
386 }
387 }
388
389 return 0;
390}
391
392static void smsdvb_unregister_client(struct smsdvb_client_t *client)
393{
394 /* must be called under clientslock */
395
396 list_del(&client->entry);
397
398 smscore_unregister_client(client->smsclient);
399 dvb_unregister_frontend(&client->frontend);
400 dvb_dmxdev_release(&client->dmxdev);
401 dvb_dmx_release(&client->demux);
402 dvb_unregister_adapter(&client->adapter);
403 kfree(client);
404}
405
406static void smsdvb_onremove(void *context)
407{
408 kmutex_lock(&g_smsdvb_clientslock);
409
410 smsdvb_unregister_client((struct smsdvb_client_t *) context);
411
412 kmutex_unlock(&g_smsdvb_clientslock);
413}
414
415static int smsdvb_start_feed(struct dvb_demux_feed *feed)
416{
417 struct smsdvb_client_t *client =
418 container_of(feed->demux, struct smsdvb_client_t, demux);
419 struct SmsMsgData_ST PidMsg;
420
421 sms_debug("add pid %d(%x)",
422 feed->pid, feed->pid);
423
424 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
425 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
426 PidMsg.xMsgHeader.msgFlags = 0;
427 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
428 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
429 PidMsg.msgData[0] = feed->pid;
430
431 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
432 return smsclient_sendrequest(client->smsclient,
433 &PidMsg, sizeof(PidMsg));
434}
435
436static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
437{
438 struct smsdvb_client_t *client =
439 container_of(feed->demux, struct smsdvb_client_t, demux);
440 struct SmsMsgData_ST PidMsg;
441
442 sms_debug("remove pid %d(%x)",
443 feed->pid, feed->pid);
444
445 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
446 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
447 PidMsg.xMsgHeader.msgFlags = 0;
448 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
449 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
450 PidMsg.msgData[0] = feed->pid;
451
452 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
453 return smsclient_sendrequest(client->smsclient,
454 &PidMsg, sizeof(PidMsg));
455}
456
457static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
458 void *buffer, size_t size,
459 struct completion *completion)
460{
461 int rc;
462
463 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
464 rc = smsclient_sendrequest(client->smsclient, buffer, size);
465 if (rc < 0)
466 return rc;
467
468 return wait_for_completion_timeout(completion,
469 msecs_to_jiffies(2000)) ?
470 0 : -ETIME;
471}
472
473static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
474{
475 int rc;
476 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
477 DVBT_BDA_CONTROL_MSG_ID,
478 HIF_TASK,
479 sizeof(struct SmsMsgHdr_ST), 0 };
480
481 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
482 &client->tune_done);
483
484 return rc;
485}
486
487static inline int led_feedback(struct smsdvb_client_t *client)
488{
489 if (client->fe_status & FE_HAS_LOCK)
490 return sms_board_led_feedback(client->coredev,
491 (client->sms_stat_dvb.ReceptionData.BER
492 == 0) ? SMS_LED_HI : SMS_LED_LO);
493 else
494 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
495}
496
497static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
498{
499 int rc;
500 struct smsdvb_client_t *client;
501 client = container_of(fe, struct smsdvb_client_t, frontend);
502
503 rc = smsdvb_send_statistics_request(client);
504
505 *stat = client->fe_status;
506
507 led_feedback(client);
508
509 return rc;
510}
511
512static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
513{
514 int rc;
515 struct smsdvb_client_t *client;
516 client = container_of(fe, struct smsdvb_client_t, frontend);
517
518 rc = smsdvb_send_statistics_request(client);
519
520 *ber = client->sms_stat_dvb.ReceptionData.BER;
521
522 led_feedback(client);
523
524 return rc;
525}
526
527static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
528{
529 int rc;
530
531 struct smsdvb_client_t *client;
532 client = container_of(fe, struct smsdvb_client_t, frontend);
533
534 rc = smsdvb_send_statistics_request(client);
535
536 if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
537 *strength = 0;
538 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
539 *strength = 100;
540 else
541 *strength =
542 (client->sms_stat_dvb.ReceptionData.InBandPwr
543 + 95) * 3 / 2;
544
545 led_feedback(client);
546
547 return rc;
548}
549
550static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
551{
552 int rc;
553 struct smsdvb_client_t *client;
554 client = container_of(fe, struct smsdvb_client_t, frontend);
555
556 rc = smsdvb_send_statistics_request(client);
557
558 *snr = client->sms_stat_dvb.ReceptionData.SNR;
559
560 led_feedback(client);
561
562 return rc;
563}
564
565static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
566{
567 int rc;
568 struct smsdvb_client_t *client;
569 client = container_of(fe, struct smsdvb_client_t, frontend);
570
571 rc = smsdvb_send_statistics_request(client);
572
573 *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
574
575 led_feedback(client);
576
577 return rc;
578}
579
580static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
581 struct dvb_frontend_tune_settings *tune)
582{
583 sms_debug("");
584
585 tune->min_delay_ms = 400;
586 tune->step_size = 250000;
587 tune->max_drift = 0;
588 return 0;
589}
590
591static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
592{
593 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
594 struct smsdvb_client_t *client =
595 container_of(fe, struct smsdvb_client_t, frontend);
596
597 struct {
598 struct SmsMsgHdr_ST Msg;
599 u32 Data[3];
600 } Msg;
601
602 int ret;
603
604 client->fe_status = FE_HAS_SIGNAL;
605 client->event_fe_state = -1;
606 client->event_unc_state = -1;
607 fe->dtv_property_cache.delivery_system = SYS_DVBT;
608
609 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
610 Msg.Msg.msgDstId = HIF_TASK;
611 Msg.Msg.msgFlags = 0;
612 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
613 Msg.Msg.msgLength = sizeof(Msg);
614 Msg.Data[0] = c->frequency;
615 Msg.Data[2] = 12000000;
616
617 sms_info("%s: freq %d band %d", __func__, c->frequency,
618 c->bandwidth_hz);
619
620 switch (c->bandwidth_hz / 1000000) {
621 case 8:
622 Msg.Data[1] = BW_8_MHZ;
623 break;
624 case 7:
625 Msg.Data[1] = BW_7_MHZ;
626 break;
627 case 6:
628 Msg.Data[1] = BW_6_MHZ;
629 break;
630 case 0:
631 return -EOPNOTSUPP;
632 default:
633 return -EINVAL;
634 }
635 /* Disable LNA, if any. An error is returned if no LNA is present */
636 ret = sms_board_lna_control(client->coredev, 0);
637 if (ret == 0) {
638 fe_status_t status;
639
640 /* tune with LNA off at first */
641 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
642 &client->tune_done);
643
644 smsdvb_read_status(fe, &status);
645
646 if (status & FE_HAS_LOCK)
647 return ret;
648
649 /* previous tune didn't lock - enable LNA and tune again */
650 sms_board_lna_control(client->coredev, 1);
651 }
652
653 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
654 &client->tune_done);
655}
656
657static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
658{
659 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
660 struct smsdvb_client_t *client =
661 container_of(fe, struct smsdvb_client_t, frontend);
662
663 struct {
664 struct SmsMsgHdr_ST Msg;
665 u32 Data[4];
666 } Msg;
667
668 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
669
670 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
671 Msg.Msg.msgDstId = HIF_TASK;
672 Msg.Msg.msgFlags = 0;
673 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
674 Msg.Msg.msgLength = sizeof(Msg);
675
676 if (c->isdbt_sb_segment_idx == -1)
677 c->isdbt_sb_segment_idx = 0;
678
679 switch (c->isdbt_sb_segment_count) {
680 case 3:
681 Msg.Data[1] = BW_ISDBT_3SEG;
682 break;
683 case 1:
684 Msg.Data[1] = BW_ISDBT_1SEG;
685 break;
686 case 0: /* AUTO */
687 switch (c->bandwidth_hz / 1000000) {
688 case 8:
689 case 7:
690 c->isdbt_sb_segment_count = 3;
691 Msg.Data[1] = BW_ISDBT_3SEG;
692 break;
693 case 6:
694 c->isdbt_sb_segment_count = 1;
695 Msg.Data[1] = BW_ISDBT_1SEG;
696 break;
697 default: /* Assumes 6 MHZ bw */
698 c->isdbt_sb_segment_count = 1;
699 c->bandwidth_hz = 6000;
700 Msg.Data[1] = BW_ISDBT_1SEG;
701 break;
702 }
703 break;
704 default:
705 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
706 return -EINVAL;
707 }
708
709 Msg.Data[0] = c->frequency;
710 Msg.Data[2] = 12000000;
711 Msg.Data[3] = c->isdbt_sb_segment_idx;
712
713 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
714 c->frequency, c->isdbt_sb_segment_count,
715 c->isdbt_sb_segment_idx);
716
717 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
718 &client->tune_done);
719}
720
721static int smsdvb_set_frontend(struct dvb_frontend *fe)
722{
723 struct smsdvb_client_t *client =
724 container_of(fe, struct smsdvb_client_t, frontend);
725 struct smscore_device_t *coredev = client->coredev;
726
727 switch (smscore_get_device_mode(coredev)) {
728 case DEVICE_MODE_DVBT:
729 case DEVICE_MODE_DVBT_BDA:
730 return smsdvb_dvbt_set_frontend(fe);
731 case DEVICE_MODE_ISDBT:
732 case DEVICE_MODE_ISDBT_BDA:
733 return smsdvb_isdbt_set_frontend(fe);
734 default:
735 return -EINVAL;
736 }
737}
738
739static int smsdvb_get_frontend(struct dvb_frontend *fe)
740{
741 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
742 struct smsdvb_client_t *client =
743 container_of(fe, struct smsdvb_client_t, frontend);
744 struct smscore_device_t *coredev = client->coredev;
745 struct TRANSMISSION_STATISTICS_S *td =
746 &client->sms_stat_dvb.TransmissionData;
747
748 switch (smscore_get_device_mode(coredev)) {
749 case DEVICE_MODE_DVBT:
750 case DEVICE_MODE_DVBT_BDA:
751 fep->frequency = td->Frequency;
752
753 switch (td->Bandwidth) {
754 case 6:
755 fep->bandwidth_hz = 6000000;
756 break;
757 case 7:
758 fep->bandwidth_hz = 7000000;
759 break;
760 case 8:
761 fep->bandwidth_hz = 8000000;
762 break;
763 }
764
765 switch (td->TransmissionMode) {
766 case 2:
767 fep->transmission_mode = TRANSMISSION_MODE_2K;
768 break;
769 case 8:
770 fep->transmission_mode = TRANSMISSION_MODE_8K;
771 }
772
773 switch (td->GuardInterval) {
774 case 0:
775 fep->guard_interval = GUARD_INTERVAL_1_32;
776 break;
777 case 1:
778 fep->guard_interval = GUARD_INTERVAL_1_16;
779 break;
780 case 2:
781 fep->guard_interval = GUARD_INTERVAL_1_8;
782 break;
783 case 3:
784 fep->guard_interval = GUARD_INTERVAL_1_4;
785 break;
786 }
787
788 switch (td->CodeRate) {
789 case 0:
790 fep->code_rate_HP = FEC_1_2;
791 break;
792 case 1:
793 fep->code_rate_HP = FEC_2_3;
794 break;
795 case 2:
796 fep->code_rate_HP = FEC_3_4;
797 break;
798 case 3:
799 fep->code_rate_HP = FEC_5_6;
800 break;
801 case 4:
802 fep->code_rate_HP = FEC_7_8;
803 break;
804 }
805
806 switch (td->LPCodeRate) {
807 case 0:
808 fep->code_rate_LP = FEC_1_2;
809 break;
810 case 1:
811 fep->code_rate_LP = FEC_2_3;
812 break;
813 case 2:
814 fep->code_rate_LP = FEC_3_4;
815 break;
816 case 3:
817 fep->code_rate_LP = FEC_5_6;
818 break;
819 case 4:
820 fep->code_rate_LP = FEC_7_8;
821 break;
822 }
823
824 switch (td->Constellation) {
825 case 0:
826 fep->modulation = QPSK;
827 break;
828 case 1:
829 fep->modulation = QAM_16;
830 break;
831 case 2:
832 fep->modulation = QAM_64;
833 break;
834 }
835
836 switch (td->Hierarchy) {
837 case 0:
838 fep->hierarchy = HIERARCHY_NONE;
839 break;
840 case 1:
841 fep->hierarchy = HIERARCHY_1;
842 break;
843 case 2:
844 fep->hierarchy = HIERARCHY_2;
845 break;
846 case 3:
847 fep->hierarchy = HIERARCHY_4;
848 break;
849 }
850
851 fep->inversion = INVERSION_AUTO;
852 break;
853 case DEVICE_MODE_ISDBT:
854 case DEVICE_MODE_ISDBT_BDA:
855 fep->frequency = td->Frequency;
856 fep->bandwidth_hz = 6000000;
857 /* todo: retrive the other parameters */
858 break;
859 default:
860 return -EINVAL;
861 }
862
863 return 0;
864}
865
866static int smsdvb_init(struct dvb_frontend *fe)
867{
868 struct smsdvb_client_t *client =
869 container_of(fe, struct smsdvb_client_t, frontend);
870
871 sms_board_power(client->coredev, 1);
872
873 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
874 return 0;
875}
876
877static int smsdvb_sleep(struct dvb_frontend *fe)
878{
879 struct smsdvb_client_t *client =
880 container_of(fe, struct smsdvb_client_t, frontend);
881
882 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
883 sms_board_power(client->coredev, 0);
884
885 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
886
887 return 0;
888}
889
890static void smsdvb_release(struct dvb_frontend *fe)
891{
892 /* do nothing */
893}
894
895static struct dvb_frontend_ops smsdvb_fe_ops = {
896 .info = {
897 .name = "Siano Mobile Digital MDTV Receiver",
898 .frequency_min = 44250000,
899 .frequency_max = 867250000,
900 .frequency_stepsize = 250000,
901 .caps = FE_CAN_INVERSION_AUTO |
902 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
903 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
904 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
905 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
906 FE_CAN_GUARD_INTERVAL_AUTO |
907 FE_CAN_RECOVER |
908 FE_CAN_HIERARCHY_AUTO,
909 },
910
911 .release = smsdvb_release,
912
913 .set_frontend = smsdvb_set_frontend,
914 .get_frontend = smsdvb_get_frontend,
915 .get_tune_settings = smsdvb_get_tune_settings,
916
917 .read_status = smsdvb_read_status,
918 .read_ber = smsdvb_read_ber,
919 .read_signal_strength = smsdvb_read_signal_strength,
920 .read_snr = smsdvb_read_snr,
921 .read_ucblocks = smsdvb_read_ucblocks,
922
923 .init = smsdvb_init,
924 .sleep = smsdvb_sleep,
925};
926
927static int smsdvb_hotplug(struct smscore_device_t *coredev,
928 struct device *device, int arrival)
929{
930 struct smsclient_params_t params;
931 struct smsdvb_client_t *client;
932 int rc;
933
934 /* device removal handled by onremove callback */
935 if (!arrival)
936 return 0;
937 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
938 if (!client) {
939 sms_err("kmalloc() failed");
940 return -ENOMEM;
941 }
942
943 /* register dvb adapter */
944 rc = dvb_register_adapter(&client->adapter,
945 sms_get_board(
946 smscore_get_board_id(coredev))->name,
947 THIS_MODULE, device, adapter_nr);
948 if (rc < 0) {
949 sms_err("dvb_register_adapter() failed %d", rc);
950 goto adapter_error;
951 }
952
953 /* init dvb demux */
954 client->demux.dmx.capabilities = DMX_TS_FILTERING;
955 client->demux.filternum = 32; /* todo: nova ??? */
956 client->demux.feednum = 32;
957 client->demux.start_feed = smsdvb_start_feed;
958 client->demux.stop_feed = smsdvb_stop_feed;
959
960 rc = dvb_dmx_init(&client->demux);
961 if (rc < 0) {
962 sms_err("dvb_dmx_init failed %d", rc);
963 goto dvbdmx_error;
964 }
965
966 /* init dmxdev */
967 client->dmxdev.filternum = 32;
968 client->dmxdev.demux = &client->demux.dmx;
969 client->dmxdev.capabilities = 0;
970
971 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
972 if (rc < 0) {
973 sms_err("dvb_dmxdev_init failed %d", rc);
974 goto dmxdev_error;
975 }
976
977 /* init and register frontend */
978 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
979 sizeof(struct dvb_frontend_ops));
980
981 switch (smscore_get_device_mode(coredev)) {
982 case DEVICE_MODE_DVBT:
983 case DEVICE_MODE_DVBT_BDA:
984 client->frontend.ops.delsys[0] = SYS_DVBT;
985 break;
986 case DEVICE_MODE_ISDBT:
987 case DEVICE_MODE_ISDBT_BDA:
988 client->frontend.ops.delsys[0] = SYS_ISDBT;
989 break;
990 }
991
992 rc = dvb_register_frontend(&client->adapter, &client->frontend);
993 if (rc < 0) {
994 sms_err("frontend registration failed %d", rc);
995 goto frontend_error;
996 }
997
998 params.initial_id = 1;
999 params.data_type = MSG_SMS_DVBT_BDA_DATA;
1000 params.onresponse_handler = smsdvb_onresponse;
1001 params.onremove_handler = smsdvb_onremove;
1002 params.context = client;
1003
1004 rc = smscore_register_client(coredev, &params, &client->smsclient);
1005 if (rc < 0) {
1006 sms_err("smscore_register_client() failed %d", rc);
1007 goto client_error;
1008 }
1009
1010 client->coredev = coredev;
1011
1012 init_completion(&client->tune_done);
1013
1014 kmutex_lock(&g_smsdvb_clientslock);
1015
1016 list_add(&client->entry, &g_smsdvb_clients);
1017
1018 kmutex_unlock(&g_smsdvb_clientslock);
1019
1020 client->event_fe_state = -1;
1021 client->event_unc_state = -1;
1022 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
1023
1024 sms_info("success");
1025 sms_board_setup(coredev);
1026
1027 return 0;
1028
1029client_error:
1030 dvb_unregister_frontend(&client->frontend);
1031
1032frontend_error:
1033 dvb_dmxdev_release(&client->dmxdev);
1034
1035dmxdev_error:
1036 dvb_dmx_release(&client->demux);
1037
1038dvbdmx_error:
1039 dvb_unregister_adapter(&client->adapter);
1040
1041adapter_error:
1042 kfree(client);
1043 return rc;
1044}
1045
1046static int __init smsdvb_module_init(void)
1047{
1048 int rc;
1049
1050 INIT_LIST_HEAD(&g_smsdvb_clients);
1051 kmutex_init(&g_smsdvb_clientslock);
1052
1053 rc = smscore_register_hotplug(smsdvb_hotplug);
1054
1055 sms_debug("");
1056
1057 return rc;
1058}
1059
1060static void __exit smsdvb_module_exit(void)
1061{
1062 smscore_unregister_hotplug(smsdvb_hotplug);
1063
1064 kmutex_lock(&g_smsdvb_clientslock);
1065
1066 while (!list_empty(&g_smsdvb_clients))
1067 smsdvb_unregister_client(
1068 (struct smsdvb_client_t *) g_smsdvb_clients.next);
1069
1070 kmutex_unlock(&g_smsdvb_clientslock);
1071}
1072
1073module_init(smsdvb_module_init);
1074module_exit(smsdvb_module_exit);
1075
1076MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
1077MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1078MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
new file mode 100644
index 000000000000..e2657c2f0109
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.c
@@ -0,0 +1,103 @@
1/****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2009, Uri Shkolnik
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 ****************************************************************/
21
22#include <linux/export.h>
23#include <asm/byteorder.h>
24
25#include "smsendian.h"
26#include "smscoreapi.h"
27
28void smsendian_handle_tx_message(void *buffer)
29{
30#ifdef __BIG_ENDIAN
31 struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
32 int i;
33 int msgWords;
34
35 switch (msg->xMsgHeader.msgType) {
36 case MSG_SMS_DATA_DOWNLOAD_REQ:
37 {
38 msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
39 break;
40 }
41
42 default:
43 msgWords = (msg->xMsgHeader.msgLength -
44 sizeof(struct SmsMsgHdr_ST))/4;
45
46 for (i = 0; i < msgWords; i++)
47 msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
48
49 break;
50 }
51#endif /* __BIG_ENDIAN */
52}
53EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
54
55void smsendian_handle_rx_message(void *buffer)
56{
57#ifdef __BIG_ENDIAN
58 struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
59 int i;
60 int msgWords;
61
62 switch (msg->xMsgHeader.msgType) {
63 case MSG_SMS_GET_VERSION_EX_RES:
64 {
65 struct SmsVersionRes_ST *ver =
66 (struct SmsVersionRes_ST *) msg;
67 ver->ChipModel = le16_to_cpu(ver->ChipModel);
68 break;
69 }
70
71 case MSG_SMS_DVBT_BDA_DATA:
72 case MSG_SMS_DAB_CHANNEL:
73 case MSG_SMS_DATA_MSG:
74 {
75 break;
76 }
77
78 default:
79 {
80 msgWords = (msg->xMsgHeader.msgLength -
81 sizeof(struct SmsMsgHdr_ST))/4;
82
83 for (i = 0; i < msgWords; i++)
84 msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
85
86 break;
87 }
88 }
89#endif /* __BIG_ENDIAN */
90}
91EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
92
93void smsendian_handle_message_header(void *msg)
94{
95#ifdef __BIG_ENDIAN
96 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
97
98 phdr->msgType = le16_to_cpu(phdr->msgType);
99 phdr->msgLength = le16_to_cpu(phdr->msgLength);
100 phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
101#endif /* __BIG_ENDIAN */
102}
103EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/common/siano/smsendian.h b/drivers/media/common/siano/smsendian.h
new file mode 100644
index 000000000000..1624d6fd367b
--- /dev/null
+++ b/drivers/media/common/siano/smsendian.h
@@ -0,0 +1,32 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2009, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 2 of the License, or
10(at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
21
22#ifndef __SMS_ENDIAN_H__
23#define __SMS_ENDIAN_H__
24
25#include <asm/byteorder.h>
26
27extern void smsendian_handle_tx_message(void *buffer);
28extern void smsendian_handle_rx_message(void *buffer);
29extern void smsendian_handle_message_header(void *msg);
30
31#endif /* __SMS_ENDIAN_H__ */
32
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
new file mode 100644
index 000000000000..37bc5c4b8ad8
--- /dev/null
+++ b/drivers/media/common/siano/smsir.c
@@ -0,0 +1,114 @@
1/****************************************************************
2
3 Siano Mobile Silicon, Inc.
4 MDTV receiver kernel modules.
5 Copyright (C) 2006-2009, Uri Shkolnik
6
7 Copyright (c) 2010 - Mauro Carvalho Chehab
8 - Ported the driver to use rc-core
9 - IR raw event decoding is now done at rc-core
10 - Code almost re-written
11
12 This program is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24
25 ****************************************************************/
26
27
28#include <linux/types.h>
29#include <linux/input.h>
30
31#include "smscoreapi.h"
32#include "smsir.h"
33#include "sms-cards.h"
34
35#define MODULE_NAME "smsmdtv"
36
37void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
38{
39 int i;
40 const s32 *samples = (const void *)buf;
41
42 for (i = 0; i < len >> 2; i++) {
43 DEFINE_IR_RAW_EVENT(ev);
44
45 ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
46 ev.pulse = (samples[i] > 0) ? false : true;
47
48 ir_raw_event_store(coredev->ir.dev, &ev);
49 }
50 ir_raw_event_handle(coredev->ir.dev);
51}
52
53int sms_ir_init(struct smscore_device_t *coredev)
54{
55 int err;
56 int board_id = smscore_get_board_id(coredev);
57 struct rc_dev *dev;
58
59 sms_log("Allocating rc device");
60 dev = rc_allocate_device();
61 if (!dev) {
62 sms_err("Not enough memory");
63 return -ENOMEM;
64 }
65
66 coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
67 coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
68 sms_log("IR port %d, timeout %d ms",
69 coredev->ir.controller, coredev->ir.timeout);
70
71 snprintf(coredev->ir.name, sizeof(coredev->ir.name),
72 "SMS IR (%s)", sms_get_board(board_id)->name);
73
74 strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
75 strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
76
77 dev->input_name = coredev->ir.name;
78 dev->input_phys = coredev->ir.phys;
79 dev->dev.parent = coredev->device;
80
81#if 0
82 /* TODO: properly initialize the parameters bellow */
83 dev->input_id.bustype = BUS_USB;
84 dev->input_id.version = 1;
85 dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
86 dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
87#endif
88
89 dev->priv = coredev;
90 dev->driver_type = RC_DRIVER_IR_RAW;
91 dev->allowed_protos = RC_TYPE_ALL;
92 dev->map_name = sms_get_board(board_id)->rc_codes;
93 dev->driver_name = MODULE_NAME;
94
95 sms_log("Input device (IR) %s is set for key events", dev->input_name);
96
97 err = rc_register_device(dev);
98 if (err < 0) {
99 sms_err("Failed to register device");
100 rc_free_device(dev);
101 return err;
102 }
103
104 coredev->ir.dev = dev;
105 return 0;
106}
107
108void sms_ir_exit(struct smscore_device_t *coredev)
109{
110 if (coredev->ir.dev)
111 rc_unregister_device(coredev->ir.dev);
112
113 sms_log("");
114}
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
new file mode 100644
index 000000000000..ae92b3a8587e
--- /dev/null
+++ b/drivers/media/common/siano/smsir.h
@@ -0,0 +1,55 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2009, Uri Shkolnik
6
7 Copyright (c) 2010 - Mauro Carvalho Chehab
8 - Ported the driver to use rc-core
9 - IR raw event decoding is now done at rc-core
10 - Code almost re-written
11
12This program is free software: you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation, either version 2 of the License, or
15(at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program. If not, see <http://www.gnu.org/licenses/>.
24
25****************************************************************/
26
27#ifndef __SMS_IR_H__
28#define __SMS_IR_H__
29
30#include <linux/input.h>
31#include <media/rc-core.h>
32
33#define IR_DEFAULT_TIMEOUT 100
34
35struct smscore_device_t;
36
37struct ir_t {
38 struct rc_dev *dev;
39 char name[40];
40 char phys[32];
41
42 char *rc_codes;
43 u64 protocol;
44
45 u32 timeout;
46 u32 controller;
47};
48
49int sms_ir_init(struct smscore_device_t *coredev);
50void sms_ir_exit(struct smscore_device_t *coredev);
51void sms_ir_event(struct smscore_device_t *coredev,
52 const char *buf, int len);
53
54#endif /* __SMS_IR_H__ */
55