aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/siano
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/siano')
-rw-r--r--drivers/media/dvb/siano/Kconfig34
-rw-r--r--drivers/media/dvb/siano/Makefile11
-rw-r--r--drivers/media/dvb/siano/sms-cards.c310
-rw-r--r--drivers/media/dvb/siano/sms-cards.h123
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c1644
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h775
-rw-r--r--drivers/media/dvb/siano/smsdvb.c962
-rw-r--r--drivers/media/dvb/siano/smsendian.c102
-rw-r--r--drivers/media/dvb/siano/smsendian.h32
-rw-r--r--drivers/media/dvb/siano/smsir.c114
-rw-r--r--drivers/media/dvb/siano/smsir.h55
-rw-r--r--drivers/media/dvb/siano/smssdio.c364
-rw-r--r--drivers/media/dvb/siano/smsusb.c582
13 files changed, 5108 insertions, 0 deletions
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
new file mode 100644
index 00000000000..bc6456eb2c4
--- /dev/null
+++ b/drivers/media/dvb/siano/Kconfig
@@ -0,0 +1,34 @@
1#
2# Siano Mobile Silicon Digital TV device configuration
3#
4
5config SMS_SIANO_MDTV
6 tristate "Siano SMS1xxx based MDTV receiver"
7 depends on DVB_CORE && RC_CORE && HAS_DMA
8 ---help---
9 Choose Y or M here if you have MDTV receiver with a Siano chipset.
10
11 To compile this driver as a module, choose M here
12 (The module will be called smsmdtv).
13
14 Further documentation on this driver can be found on the WWW
15 at http://www.siano-ms.com/
16
17if SMS_SIANO_MDTV
18menu "Siano module components"
19
20# Hardware interfaces support
21
22config SMS_USB_DRV
23 tristate "USB interface support"
24 depends on DVB_CORE && USB
25 ---help---
26 Choose if you would like to have Siano's support for USB interface
27
28config SMS_SDIO_DRV
29 tristate "SDIO interface support"
30 depends on DVB_CORE && MMC
31 ---help---
32 Choose if you would like to have Siano's support for SDIO interface
33endmenu
34endif # SMS_SIANO_MDTV
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
new file mode 100644
index 00000000000..c54140b5ab5
--- /dev/null
+++ b/drivers/media/dvb/siano/Makefile
@@ -0,0 +1,11 @@
1
2smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
3
4obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
5obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
6obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
7
8EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
9
10EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
11
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
new file mode 100644
index 00000000000..af121db88ea
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -0,0 +1,310 @@
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
23static int sms_dbg;
24module_param_named(cards_dbg, sms_dbg, int, 0644);
25MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))");
26
27static struct sms_board sms_boards[] = {
28 [SMS_BOARD_UNKNOWN] = {
29 .name = "Unknown board",
30 },
31 [SMS1XXX_BOARD_SIANO_STELLAR] = {
32 .name = "Siano Stellar Digital Receiver",
33 .type = SMS_STELLAR,
34 },
35 [SMS1XXX_BOARD_SIANO_NOVA_A] = {
36 .name = "Siano Nova A Digital Receiver",
37 .type = SMS_NOVA_A0,
38 },
39 [SMS1XXX_BOARD_SIANO_NOVA_B] = {
40 .name = "Siano Nova B Digital Receiver",
41 .type = SMS_NOVA_B0,
42 },
43 [SMS1XXX_BOARD_SIANO_VEGA] = {
44 .name = "Siano Vega Digital Receiver",
45 .type = SMS_VEGA,
46 },
47 [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
48 .name = "Hauppauge Catamount",
49 .type = SMS_STELLAR,
50 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
51 },
52 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
53 .name = "Hauppauge Okemo-A",
54 .type = SMS_NOVA_A0,
55 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
56 },
57 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
58 .name = "Hauppauge Okemo-B",
59 .type = SMS_NOVA_B0,
60 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
61 },
62 [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
63 .name = "Hauppauge WinTV MiniStick",
64 .type = SMS_NOVA_B0,
65 .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
66 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
67 .rc_codes = RC_MAP_HAUPPAUGE,
68 .board_cfg.leds_power = 26,
69 .board_cfg.led0 = 27,
70 .board_cfg.led1 = 28,
71 .board_cfg.ir = 9,
72 .led_power = 26,
73 .led_lo = 27,
74 .led_hi = 28,
75 },
76 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = {
77 .name = "Hauppauge WinTV MiniCard",
78 .type = SMS_NOVA_B0,
79 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
80 .lna_ctrl = 29,
81 .board_cfg.foreign_lna0_ctrl = 29,
82 .rf_switch = 17,
83 .board_cfg.rf_switch_uhf = 17,
84 },
85 [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
86 .name = "Hauppauge WinTV MiniCard",
87 .type = SMS_NOVA_B0,
88 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
89 .lna_ctrl = -1,
90 },
91 [SMS1XXX_BOARD_SIANO_NICE] = {
92 /* 11 */
93 .name = "Siano Nice Digital Receiver",
94 .type = SMS_NOVA_B0,
95 },
96 [SMS1XXX_BOARD_SIANO_VENICE] = {
97 /* 12 */
98 .name = "Siano Venice Digital Receiver",
99 .type = SMS_VEGA,
100 },
101};
102
103struct sms_board *sms_get_board(unsigned id)
104{
105 BUG_ON(id >= ARRAY_SIZE(sms_boards));
106
107 return &sms_boards[id];
108}
109EXPORT_SYMBOL_GPL(sms_get_board);
110static inline void sms_gpio_assign_11xx_default_led_config(
111 struct smscore_gpio_config *pGpioConfig) {
112 pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
113 pGpioConfig->InputCharacteristics =
114 SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
115 pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
116 pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
117 pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
118}
119
120int sms_board_event(struct smscore_device_t *coredev,
121 enum SMS_BOARD_EVENTS gevent) {
122 struct smscore_gpio_config MyGpioConfig;
123
124 sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
125
126 switch (gevent) {
127 case BOARD_EVENT_POWER_INIT: /* including hotplug */
128 break; /* BOARD_EVENT_BIND */
129
130 case BOARD_EVENT_POWER_SUSPEND:
131 break; /* BOARD_EVENT_POWER_SUSPEND */
132
133 case BOARD_EVENT_POWER_RESUME:
134 break; /* BOARD_EVENT_POWER_RESUME */
135
136 case BOARD_EVENT_BIND:
137 break; /* BOARD_EVENT_BIND */
138
139 case BOARD_EVENT_SCAN_PROG:
140 break; /* BOARD_EVENT_SCAN_PROG */
141 case BOARD_EVENT_SCAN_COMP:
142 break; /* BOARD_EVENT_SCAN_COMP */
143 case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
144 break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
145 case BOARD_EVENT_FE_LOCK:
146 break; /* BOARD_EVENT_FE_LOCK */
147 case BOARD_EVENT_FE_UNLOCK:
148 break; /* BOARD_EVENT_FE_UNLOCK */
149 case BOARD_EVENT_DEMOD_LOCK:
150 break; /* BOARD_EVENT_DEMOD_LOCK */
151 case BOARD_EVENT_DEMOD_UNLOCK:
152 break; /* BOARD_EVENT_DEMOD_UNLOCK */
153 case BOARD_EVENT_RECEPTION_MAX_4:
154 break; /* BOARD_EVENT_RECEPTION_MAX_4 */
155 case BOARD_EVENT_RECEPTION_3:
156 break; /* BOARD_EVENT_RECEPTION_3 */
157 case BOARD_EVENT_RECEPTION_2:
158 break; /* BOARD_EVENT_RECEPTION_2 */
159 case BOARD_EVENT_RECEPTION_1:
160 break; /* BOARD_EVENT_RECEPTION_1 */
161 case BOARD_EVENT_RECEPTION_LOST_0:
162 break; /* BOARD_EVENT_RECEPTION_LOST_0 */
163 case BOARD_EVENT_MULTIPLEX_OK:
164 break; /* BOARD_EVENT_MULTIPLEX_OK */
165 case BOARD_EVENT_MULTIPLEX_ERRORS:
166 break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
167
168 default:
169 sms_err("Unknown SMS board event");
170 break;
171 }
172 return 0;
173}
174EXPORT_SYMBOL_GPL(sms_board_event);
175
176static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
177{
178 int lvl, ret;
179 u32 gpio;
180 struct smscore_config_gpio gpioconfig = {
181 .direction = SMS_GPIO_DIRECTION_OUTPUT,
182 .pullupdown = SMS_GPIO_PULLUPDOWN_NONE,
183 .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
184 .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST,
185 .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA,
186 };
187
188 if (pin == 0)
189 return -EINVAL;
190
191 if (pin < 0) {
192 /* inverted gpio */
193 gpio = pin * -1;
194 lvl = enable ? 0 : 1;
195 } else {
196 gpio = pin;
197 lvl = enable ? 1 : 0;
198 }
199
200 ret = smscore_configure_gpio(coredev, gpio, &gpioconfig);
201 if (ret < 0)
202 return ret;
203
204 return smscore_set_gpio(coredev, gpio, lvl);
205}
206
207int sms_board_setup(struct smscore_device_t *coredev)
208{
209 int board_id = smscore_get_board_id(coredev);
210 struct sms_board *board = sms_get_board(board_id);
211
212 switch (board_id) {
213 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
214 /* turn off all LEDs */
215 sms_set_gpio(coredev, board->led_power, 0);
216 sms_set_gpio(coredev, board->led_hi, 0);
217 sms_set_gpio(coredev, board->led_lo, 0);
218 break;
219 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
220 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
221 /* turn off LNA */
222 sms_set_gpio(coredev, board->lna_ctrl, 0);
223 break;
224 }
225 return 0;
226}
227EXPORT_SYMBOL_GPL(sms_board_setup);
228
229int sms_board_power(struct smscore_device_t *coredev, int onoff)
230{
231 int board_id = smscore_get_board_id(coredev);
232 struct sms_board *board = sms_get_board(board_id);
233
234 switch (board_id) {
235 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
236 /* power LED */
237 sms_set_gpio(coredev,
238 board->led_power, onoff ? 1 : 0);
239 break;
240 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
241 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
242 /* LNA */
243 if (!onoff)
244 sms_set_gpio(coredev, board->lna_ctrl, 0);
245 break;
246 }
247 return 0;
248}
249EXPORT_SYMBOL_GPL(sms_board_power);
250
251int sms_board_led_feedback(struct smscore_device_t *coredev, int led)
252{
253 int board_id = smscore_get_board_id(coredev);
254 struct sms_board *board = sms_get_board(board_id);
255
256 /* dont touch GPIO if LEDs are already set */
257 if (smscore_led_state(coredev, -1) == led)
258 return 0;
259
260 switch (board_id) {
261 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
262 sms_set_gpio(coredev,
263 board->led_lo, (led & SMS_LED_LO) ? 1 : 0);
264 sms_set_gpio(coredev,
265 board->led_hi, (led & SMS_LED_HI) ? 1 : 0);
266
267 smscore_led_state(coredev, led);
268 break;
269 }
270 return 0;
271}
272EXPORT_SYMBOL_GPL(sms_board_led_feedback);
273
274int sms_board_lna_control(struct smscore_device_t *coredev, int onoff)
275{
276 int board_id = smscore_get_board_id(coredev);
277 struct sms_board *board = sms_get_board(board_id);
278
279 sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled");
280
281 switch (board_id) {
282 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
283 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
284 sms_set_gpio(coredev,
285 board->rf_switch, onoff ? 1 : 0);
286 return sms_set_gpio(coredev,
287 board->lna_ctrl, onoff ? 1 : 0);
288 }
289 return -EINVAL;
290}
291EXPORT_SYMBOL_GPL(sms_board_lna_control);
292
293int sms_board_load_modules(int id)
294{
295 switch (id) {
296 case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT:
297 case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
298 case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
299 case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
300 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
301 case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
302 request_module("smsdvb");
303 break;
304 default:
305 /* do nothing */
306 break;
307 }
308 return 0;
309}
310EXPORT_SYMBOL_GPL(sms_board_load_modules);
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
new file mode 100644
index 00000000000..d8cdf756f7c
--- /dev/null
+++ b/drivers/media/dvb/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/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
new file mode 100644
index 00000000000..7331e8450d1
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -0,0 +1,1644 @@
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 list_head *next, *first;
280 int rc = 0;
281
282 /* note: must be called under g_deviceslock */
283
284 first = &g_smscore_notifyees;
285
286 for (next = first->next; next != first; next = next->next) {
287 rc = ((struct smscore_device_notifyee_t *) next)->
288 hotplug(coredev, device, arrival);
289 if (rc < 0)
290 break;
291 }
292
293 return rc;
294}
295
296static struct
297smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
298 dma_addr_t common_buffer_phys)
299{
300 struct smscore_buffer_t *cb =
301 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
302 if (!cb) {
303 sms_info("kmalloc(...) failed");
304 return NULL;
305 }
306
307 cb->p = buffer;
308 cb->offset_in_common = buffer - (u8 *) common_buffer;
309 cb->phys = common_buffer_phys + cb->offset_in_common;
310
311 return cb;
312}
313
314/**
315 * creates coredev object for a device, prepares buffers,
316 * creates buffer mappings, notifies registered hotplugs about new device.
317 *
318 * @param params device pointer to struct with device specific parameters
319 * and handlers
320 * @param coredev pointer to a value that receives created coredev object
321 *
322 * @return 0 on success, <0 on error.
323 */
324int smscore_register_device(struct smsdevice_params_t *params,
325 struct smscore_device_t **coredev)
326{
327 struct smscore_device_t *dev;
328 u8 *buffer;
329
330 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
331 if (!dev) {
332 sms_info("kzalloc(...) failed");
333 return -ENOMEM;
334 }
335
336 /* init list entry so it could be safe in smscore_unregister_device */
337 INIT_LIST_HEAD(&dev->entry);
338
339 /* init queues */
340 INIT_LIST_HEAD(&dev->clients);
341 INIT_LIST_HEAD(&dev->buffers);
342
343 /* init locks */
344 spin_lock_init(&dev->clientslock);
345 spin_lock_init(&dev->bufferslock);
346
347 /* init completion events */
348 init_completion(&dev->version_ex_done);
349 init_completion(&dev->data_download_done);
350 init_completion(&dev->trigger_done);
351 init_completion(&dev->init_device_done);
352 init_completion(&dev->reload_start_done);
353 init_completion(&dev->resume_done);
354 init_completion(&dev->gpio_configuration_done);
355 init_completion(&dev->gpio_set_level_done);
356 init_completion(&dev->gpio_get_level_done);
357 init_completion(&dev->ir_init_done);
358
359 /* Buffer management */
360 init_waitqueue_head(&dev->buffer_mng_waitq);
361
362 /* alloc common buffer */
363 dev->common_buffer_size = params->buffer_size * params->num_buffers;
364 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
365 &dev->common_buffer_phys,
366 GFP_KERNEL | GFP_DMA);
367 if (!dev->common_buffer) {
368 smscore_unregister_device(dev);
369 return -ENOMEM;
370 }
371
372 /* prepare dma buffers */
373 for (buffer = dev->common_buffer;
374 dev->num_buffers < params->num_buffers;
375 dev->num_buffers++, buffer += params->buffer_size) {
376 struct smscore_buffer_t *cb =
377 smscore_createbuffer(buffer, dev->common_buffer,
378 dev->common_buffer_phys);
379 if (!cb) {
380 smscore_unregister_device(dev);
381 return -ENOMEM;
382 }
383
384 smscore_putbuffer(dev, cb);
385 }
386
387 sms_info("allocated %d buffers", dev->num_buffers);
388
389 dev->mode = DEVICE_MODE_NONE;
390 dev->context = params->context;
391 dev->device = params->device;
392 dev->setmode_handler = params->setmode_handler;
393 dev->detectmode_handler = params->detectmode_handler;
394 dev->sendrequest_handler = params->sendrequest_handler;
395 dev->preload_handler = params->preload_handler;
396 dev->postload_handler = params->postload_handler;
397
398 dev->device_flags = params->flags;
399 strcpy(dev->devpath, params->devpath);
400
401 smscore_registry_settype(dev->devpath, params->device_type);
402
403 /* add device to devices list */
404 kmutex_lock(&g_smscore_deviceslock);
405 list_add(&dev->entry, &g_smscore_devices);
406 kmutex_unlock(&g_smscore_deviceslock);
407
408 *coredev = dev;
409
410 sms_info("device %p created", dev);
411
412 return 0;
413}
414EXPORT_SYMBOL_GPL(smscore_register_device);
415
416
417static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
418 void *buffer, size_t size, struct completion *completion) {
419 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
420 if (rc < 0) {
421 sms_info("sendrequest returned error %d", rc);
422 return rc;
423 }
424
425 return wait_for_completion_timeout(completion,
426 msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
427 0 : -ETIME;
428}
429
430/**
431 * Starts & enables IR operations
432 *
433 * @return 0 on success, < 0 on error.
434 */
435static int smscore_init_ir(struct smscore_device_t *coredev)
436{
437 int ir_io;
438 int rc;
439 void *buffer;
440
441 coredev->ir.dev = NULL;
442 ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
443 if (ir_io) {/* only if IR port exist we use IR sub-module */
444 sms_info("IR loading");
445 rc = sms_ir_init(coredev);
446
447 if (rc != 0)
448 sms_err("Error initialization DTV IR sub-module");
449 else {
450 buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
451 SMS_DMA_ALIGNMENT,
452 GFP_KERNEL | GFP_DMA);
453 if (buffer) {
454 struct SmsMsgData_ST2 *msg =
455 (struct SmsMsgData_ST2 *)
456 SMS_ALIGN_ADDRESS(buffer);
457
458 SMS_INIT_MSG(&msg->xMsgHeader,
459 MSG_SMS_START_IR_REQ,
460 sizeof(struct SmsMsgData_ST2));
461 msg->msgData[0] = coredev->ir.controller;
462 msg->msgData[1] = coredev->ir.timeout;
463
464 smsendian_handle_tx_message(
465 (struct SmsMsgHdr_ST2 *)msg);
466 rc = smscore_sendrequest_and_wait(coredev, msg,
467 msg->xMsgHeader. msgLength,
468 &coredev->ir_init_done);
469
470 kfree(buffer);
471 } else
472 sms_err
473 ("Sending IR initialization message failed");
474 }
475 } else
476 sms_info("IR port has not been detected");
477
478 return 0;
479}
480
481/**
482 * sets initial device mode and notifies client hotplugs that device is ready
483 *
484 * @param coredev pointer to a coredev object returned by
485 * smscore_register_device
486 *
487 * @return 0 on success, <0 on error.
488 */
489int smscore_start_device(struct smscore_device_t *coredev)
490{
491 int rc = smscore_set_device_mode(
492 coredev, smscore_registry_getmode(coredev->devpath));
493 if (rc < 0) {
494 sms_info("set device mode faile , rc %d", rc);
495 return rc;
496 }
497
498 kmutex_lock(&g_smscore_deviceslock);
499
500 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
501 smscore_init_ir(coredev);
502
503 sms_info("device %p started, rc %d", coredev, rc);
504
505 kmutex_unlock(&g_smscore_deviceslock);
506
507 return rc;
508}
509EXPORT_SYMBOL_GPL(smscore_start_device);
510
511
512static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
513 void *buffer, size_t size)
514{
515 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
516 struct SmsMsgHdr_ST *msg;
517 u32 mem_address;
518 u8 *payload = firmware->Payload;
519 int rc = 0;
520 firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
521 firmware->Length = le32_to_cpu(firmware->Length);
522
523 mem_address = firmware->StartAddress;
524
525 sms_info("loading FW to addr 0x%x size %d",
526 mem_address, firmware->Length);
527 if (coredev->preload_handler) {
528 rc = coredev->preload_handler(coredev->context);
529 if (rc < 0)
530 return rc;
531 }
532
533 /* PAGE_SIZE buffer shall be enough and dma aligned */
534 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
535 if (!msg)
536 return -ENOMEM;
537
538 if (coredev->mode != DEVICE_MODE_NONE) {
539 sms_debug("sending reload command.");
540 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
541 sizeof(struct SmsMsgHdr_ST));
542 rc = smscore_sendrequest_and_wait(coredev, msg,
543 msg->msgLength,
544 &coredev->reload_start_done);
545 mem_address = *(u32 *) &payload[20];
546 }
547
548 while (size && rc >= 0) {
549 struct SmsDataDownload_ST *DataMsg =
550 (struct SmsDataDownload_ST *) msg;
551 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
552
553 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
554 (u16)(sizeof(struct SmsMsgHdr_ST) +
555 sizeof(u32) + payload_size));
556
557 DataMsg->MemAddr = mem_address;
558 memcpy(DataMsg->Payload, payload, payload_size);
559
560 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
561 (coredev->mode == DEVICE_MODE_NONE))
562 rc = coredev->sendrequest_handler(
563 coredev->context, DataMsg,
564 DataMsg->xMsgHeader.msgLength);
565 else
566 rc = smscore_sendrequest_and_wait(
567 coredev, DataMsg,
568 DataMsg->xMsgHeader.msgLength,
569 &coredev->data_download_done);
570
571 payload += payload_size;
572 size -= payload_size;
573 mem_address += payload_size;
574 }
575
576 if (rc >= 0) {
577 if (coredev->mode == DEVICE_MODE_NONE) {
578 struct SmsMsgData_ST *TriggerMsg =
579 (struct SmsMsgData_ST *) msg;
580
581 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
582 sizeof(struct SmsMsgHdr_ST) +
583 sizeof(u32) * 5);
584
585 TriggerMsg->msgData[0] = firmware->StartAddress;
586 /* Entry point */
587 TriggerMsg->msgData[1] = 5; /* Priority */
588 TriggerMsg->msgData[2] = 0x200; /* Stack size */
589 TriggerMsg->msgData[3] = 0; /* Parameter */
590 TriggerMsg->msgData[4] = 4; /* Task ID */
591
592 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
593 rc = coredev->sendrequest_handler(
594 coredev->context, TriggerMsg,
595 TriggerMsg->xMsgHeader.msgLength);
596 msleep(100);
597 } else
598 rc = smscore_sendrequest_and_wait(
599 coredev, TriggerMsg,
600 TriggerMsg->xMsgHeader.msgLength,
601 &coredev->trigger_done);
602 } else {
603 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
604 sizeof(struct SmsMsgHdr_ST));
605
606 rc = coredev->sendrequest_handler(coredev->context,
607 msg, msg->msgLength);
608 }
609 msleep(500);
610 }
611
612 sms_debug("rc=%d, postload=%p ", rc,
613 coredev->postload_handler);
614
615 kfree(msg);
616
617 return ((rc >= 0) && coredev->postload_handler) ?
618 coredev->postload_handler(coredev->context) :
619 rc;
620}
621
622/**
623 * loads specified firmware into a buffer and calls device loadfirmware_handler
624 *
625 * @param coredev pointer to a coredev object returned by
626 * smscore_register_device
627 * @param filename null-terminated string specifies firmware file name
628 * @param loadfirmware_handler device handler that loads firmware
629 *
630 * @return 0 on success, <0 on error.
631 */
632static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
633 char *filename,
634 loadfirmware_t loadfirmware_handler)
635{
636 int rc = -ENOENT;
637 const struct firmware *fw;
638 u8 *fw_buffer;
639
640 if (loadfirmware_handler == NULL && !(coredev->device_flags &
641 SMS_DEVICE_FAMILY2))
642 return -EINVAL;
643
644 rc = request_firmware(&fw, filename, coredev->device);
645 if (rc < 0) {
646 sms_info("failed to open \"%s\"", filename);
647 return rc;
648 }
649 sms_info("read FW %s, size=%zd", filename, fw->size);
650 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
651 GFP_KERNEL | GFP_DMA);
652 if (fw_buffer) {
653 memcpy(fw_buffer, fw->data, fw->size);
654
655 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
656 smscore_load_firmware_family2(coredev,
657 fw_buffer,
658 fw->size) :
659 loadfirmware_handler(coredev->context,
660 fw_buffer, fw->size);
661
662 kfree(fw_buffer);
663 } else {
664 sms_info("failed to allocate firmware buffer");
665 rc = -ENOMEM;
666 }
667
668 release_firmware(fw);
669
670 return rc;
671}
672
673/**
674 * notifies all clients registered with the device, notifies hotplugs,
675 * frees all buffers and coredev object
676 *
677 * @param coredev pointer to a coredev object returned by
678 * smscore_register_device
679 *
680 * @return 0 on success, <0 on error.
681 */
682void smscore_unregister_device(struct smscore_device_t *coredev)
683{
684 struct smscore_buffer_t *cb;
685 int num_buffers = 0;
686 int retry = 0;
687
688 kmutex_lock(&g_smscore_deviceslock);
689
690 /* Release input device (IR) resources */
691 sms_ir_exit(coredev);
692
693 smscore_notify_clients(coredev);
694 smscore_notify_callbacks(coredev, NULL, 0);
695
696 /* at this point all buffers should be back
697 * onresponse must no longer be called */
698
699 while (1) {
700 while (!list_empty(&coredev->buffers)) {
701 cb = (struct smscore_buffer_t *) coredev->buffers.next;
702 list_del(&cb->entry);
703 kfree(cb);
704 num_buffers++;
705 }
706 if (num_buffers == coredev->num_buffers)
707 break;
708 if (++retry > 10) {
709 sms_info("exiting although "
710 "not all buffers released.");
711 break;
712 }
713
714 sms_info("waiting for %d buffer(s)",
715 coredev->num_buffers - num_buffers);
716 msleep(100);
717 }
718
719 sms_info("freed %d buffers", num_buffers);
720
721 if (coredev->common_buffer)
722 dma_free_coherent(NULL, coredev->common_buffer_size,
723 coredev->common_buffer, coredev->common_buffer_phys);
724
725 if (coredev->fw_buf != NULL)
726 kfree(coredev->fw_buf);
727
728 list_del(&coredev->entry);
729 kfree(coredev);
730
731 kmutex_unlock(&g_smscore_deviceslock);
732
733 sms_info("device %p destroyed", coredev);
734}
735EXPORT_SYMBOL_GPL(smscore_unregister_device);
736
737static int smscore_detect_mode(struct smscore_device_t *coredev)
738{
739 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
740 GFP_KERNEL | GFP_DMA);
741 struct SmsMsgHdr_ST *msg =
742 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
743 int rc;
744
745 if (!buffer)
746 return -ENOMEM;
747
748 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
749 sizeof(struct SmsMsgHdr_ST));
750
751 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
752 &coredev->version_ex_done);
753 if (rc == -ETIME) {
754 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
755
756 if (wait_for_completion_timeout(&coredev->resume_done,
757 msecs_to_jiffies(5000))) {
758 rc = smscore_sendrequest_and_wait(
759 coredev, msg, msg->msgLength,
760 &coredev->version_ex_done);
761 if (rc < 0)
762 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
763 "second try, rc %d", rc);
764 } else
765 rc = -ETIME;
766 }
767
768 kfree(buffer);
769
770 return rc;
771}
772
773static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
774 /*Stellar NOVA A0 Nova B0 VEGA*/
775 /*DVBT*/
776 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
777 /*DVBH*/
778 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
779 /*TDMB*/
780 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
781 /*DABIP*/
782 {"none", "none", "none", "none"},
783 /*BDA*/
784 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
785 /*ISDBT*/
786 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
787 /*ISDBTBDA*/
788 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
789 /*CMMB*/
790 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
791};
792
793static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
794 int mode, enum sms_device_type_st type)
795{
796 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
797 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
798}
799
800/**
801 * calls device handler to change mode of operation
802 * NOTE: stellar/usb may disconnect when changing mode
803 *
804 * @param coredev pointer to a coredev object returned by
805 * smscore_register_device
806 * @param mode requested mode of operation
807 *
808 * @return 0 on success, <0 on error.
809 */
810int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
811{
812 void *buffer;
813 int rc = 0;
814 enum sms_device_type_st type;
815
816 sms_debug("set device mode to %d", mode);
817 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
818 if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
819 sms_err("invalid mode specified %d", mode);
820 return -EINVAL;
821 }
822
823 smscore_registry_setmode(coredev->devpath, mode);
824
825 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
826 rc = smscore_detect_mode(coredev);
827 if (rc < 0) {
828 sms_err("mode detect failed %d", rc);
829 return rc;
830 }
831 }
832
833 if (coredev->mode == mode) {
834 sms_info("device mode %d already set", mode);
835 return 0;
836 }
837
838 if (!(coredev->modes_supported & (1 << mode))) {
839 char *fw_filename;
840
841 type = smscore_registry_gettype(coredev->devpath);
842 fw_filename = sms_get_fw_name(coredev, mode, type);
843
844 rc = smscore_load_firmware_from_file(coredev,
845 fw_filename, NULL);
846 if (rc < 0) {
847 sms_warn("error %d loading firmware: %s, "
848 "trying again with default firmware",
849 rc, fw_filename);
850
851 /* try again with the default firmware */
852 fw_filename = smscore_fw_lkup[mode][type];
853 rc = smscore_load_firmware_from_file(coredev,
854 fw_filename, NULL);
855
856 if (rc < 0) {
857 sms_warn("error %d loading "
858 "firmware: %s", rc,
859 fw_filename);
860 return rc;
861 }
862 }
863 sms_log("firmware download success: %s", fw_filename);
864 } else
865 sms_info("mode %d supported by running "
866 "firmware", mode);
867
868 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
869 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
870 if (buffer) {
871 struct SmsMsgData_ST *msg =
872 (struct SmsMsgData_ST *)
873 SMS_ALIGN_ADDRESS(buffer);
874
875 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
876 sizeof(struct SmsMsgData_ST));
877 msg->msgData[0] = mode;
878
879 rc = smscore_sendrequest_and_wait(
880 coredev, msg, msg->xMsgHeader.msgLength,
881 &coredev->init_device_done);
882
883 kfree(buffer);
884 } else {
885 sms_err("Could not allocate buffer for "
886 "init device message.");
887 rc = -ENOMEM;
888 }
889 } else {
890 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
891 sms_err("invalid mode specified %d", mode);
892 return -EINVAL;
893 }
894
895 smscore_registry_setmode(coredev->devpath, mode);
896
897 if (coredev->detectmode_handler)
898 coredev->detectmode_handler(coredev->context,
899 &coredev->mode);
900
901 if (coredev->mode != mode && coredev->setmode_handler)
902 rc = coredev->setmode_handler(coredev->context, mode);
903 }
904
905 if (rc >= 0) {
906 coredev->mode = mode;
907 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
908 }
909
910 if (rc < 0)
911 sms_err("return error code %d.", rc);
912 return rc;
913}
914
915/**
916 * calls device handler to get current mode of operation
917 *
918 * @param coredev pointer to a coredev object returned by
919 * smscore_register_device
920 *
921 * @return current mode
922 */
923int smscore_get_device_mode(struct smscore_device_t *coredev)
924{
925 return coredev->mode;
926}
927EXPORT_SYMBOL_GPL(smscore_get_device_mode);
928
929/**
930 * find client by response id & type within the clients list.
931 * return client handle or NULL.
932 *
933 * @param coredev pointer to a coredev object returned by
934 * smscore_register_device
935 * @param data_type client data type (SMS_DONT_CARE for all types)
936 * @param id client id (SMS_DONT_CARE for all id)
937 *
938 */
939static struct
940smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
941 int data_type, int id)
942{
943 struct smscore_client_t *client = NULL;
944 struct list_head *next, *first;
945 unsigned long flags;
946 struct list_head *firstid, *nextid;
947
948
949 spin_lock_irqsave(&coredev->clientslock, flags);
950 first = &coredev->clients;
951 for (next = first->next;
952 (next != first) && !client;
953 next = next->next) {
954 firstid = &((struct smscore_client_t *)next)->idlist;
955 for (nextid = firstid->next;
956 nextid != firstid;
957 nextid = nextid->next) {
958 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
959 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
960 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
961 client = (struct smscore_client_t *) next;
962 break;
963 }
964 }
965 }
966 spin_unlock_irqrestore(&coredev->clientslock, flags);
967 return client;
968}
969
970/**
971 * find client by response id/type, call clients onresponse handler
972 * return buffer to pool on error
973 *
974 * @param coredev pointer to a coredev object returned by
975 * smscore_register_device
976 * @param cb pointer to response buffer descriptor
977 *
978 */
979void smscore_onresponse(struct smscore_device_t *coredev,
980 struct smscore_buffer_t *cb) {
981 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
982 + cb->offset);
983 struct smscore_client_t *client;
984 int rc = -EBUSY;
985 static unsigned long last_sample_time; /* = 0; */
986 static int data_total; /* = 0; */
987 unsigned long time_now = jiffies_to_msecs(jiffies);
988
989 if (!last_sample_time)
990 last_sample_time = time_now;
991
992 if (time_now - last_sample_time > 10000) {
993 sms_debug("\ndata rate %d bytes/secs",
994 (int)((data_total * 1000) /
995 (time_now - last_sample_time)));
996
997 last_sample_time = time_now;
998 data_total = 0;
999 }
1000
1001 data_total += cb->size;
1002 /* Do we need to re-route? */
1003 if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
1004 (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
1005 if (coredev->mode == DEVICE_MODE_DVBT_BDA)
1006 phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
1007 }
1008
1009
1010 client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1011
1012 /* If no client registered for type & id,
1013 * check for control client where type is not registered */
1014 if (client)
1015 rc = client->onresponse_handler(client->context, cb);
1016
1017 if (rc < 0) {
1018 switch (phdr->msgType) {
1019 case MSG_SMS_GET_VERSION_EX_RES:
1020 {
1021 struct SmsVersionRes_ST *ver =
1022 (struct SmsVersionRes_ST *) phdr;
1023 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1024 "id %d prots 0x%x ver %d.%d",
1025 ver->FirmwareId, ver->SupportedProtocols,
1026 ver->RomVersionMajor, ver->RomVersionMinor);
1027
1028 coredev->mode = ver->FirmwareId == 255 ?
1029 DEVICE_MODE_NONE : ver->FirmwareId;
1030 coredev->modes_supported = ver->SupportedProtocols;
1031
1032 complete(&coredev->version_ex_done);
1033 break;
1034 }
1035 case MSG_SMS_INIT_DEVICE_RES:
1036 sms_debug("MSG_SMS_INIT_DEVICE_RES");
1037 complete(&coredev->init_device_done);
1038 break;
1039 case MSG_SW_RELOAD_START_RES:
1040 sms_debug("MSG_SW_RELOAD_START_RES");
1041 complete(&coredev->reload_start_done);
1042 break;
1043 case MSG_SMS_DATA_DOWNLOAD_RES:
1044 complete(&coredev->data_download_done);
1045 break;
1046 case MSG_SW_RELOAD_EXEC_RES:
1047 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1048 break;
1049 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1050 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1051 complete(&coredev->trigger_done);
1052 break;
1053 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1054 complete(&coredev->resume_done);
1055 break;
1056 case MSG_SMS_GPIO_CONFIG_EX_RES:
1057 sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1058 complete(&coredev->gpio_configuration_done);
1059 break;
1060 case MSG_SMS_GPIO_SET_LEVEL_RES:
1061 sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1062 complete(&coredev->gpio_set_level_done);
1063 break;
1064 case MSG_SMS_GPIO_GET_LEVEL_RES:
1065 {
1066 u32 *msgdata = (u32 *) phdr;
1067 coredev->gpio_get_res = msgdata[1];
1068 sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1069 coredev->gpio_get_res);
1070 complete(&coredev->gpio_get_level_done);
1071 break;
1072 }
1073 case MSG_SMS_START_IR_RES:
1074 complete(&coredev->ir_init_done);
1075 break;
1076 case MSG_SMS_IR_SAMPLES_IND:
1077 sms_ir_event(coredev,
1078 (const char *)
1079 ((char *)phdr
1080 + sizeof(struct SmsMsgHdr_ST)),
1081 (int)phdr->msgLength
1082 - sizeof(struct SmsMsgHdr_ST));
1083 break;
1084
1085 default:
1086 break;
1087 }
1088 smscore_putbuffer(coredev, cb);
1089 }
1090}
1091EXPORT_SYMBOL_GPL(smscore_onresponse);
1092
1093/**
1094 * return pointer to next free buffer descriptor from core pool
1095 *
1096 * @param coredev pointer to a coredev object returned by
1097 * smscore_register_device
1098 *
1099 * @return pointer to descriptor on success, NULL on error.
1100 */
1101
1102struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
1103{
1104 struct smscore_buffer_t *cb = NULL;
1105 unsigned long flags;
1106
1107 spin_lock_irqsave(&coredev->bufferslock, flags);
1108 if (!list_empty(&coredev->buffers)) {
1109 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1110 list_del(&cb->entry);
1111 }
1112 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1113 return cb;
1114}
1115
1116struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1117{
1118 struct smscore_buffer_t *cb = NULL;
1119
1120 wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
1121
1122 return cb;
1123}
1124EXPORT_SYMBOL_GPL(smscore_getbuffer);
1125
1126/**
1127 * return buffer descriptor to a pool
1128 *
1129 * @param coredev pointer to a coredev object returned by
1130 * smscore_register_device
1131 * @param cb pointer buffer descriptor
1132 *
1133 */
1134void smscore_putbuffer(struct smscore_device_t *coredev,
1135 struct smscore_buffer_t *cb) {
1136 wake_up_interruptible(&coredev->buffer_mng_waitq);
1137 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1138}
1139EXPORT_SYMBOL_GPL(smscore_putbuffer);
1140
1141static int smscore_validate_client(struct smscore_device_t *coredev,
1142 struct smscore_client_t *client,
1143 int data_type, int id)
1144{
1145 struct smscore_idlist_t *listentry;
1146 struct smscore_client_t *registered_client;
1147
1148 if (!client) {
1149 sms_err("bad parameter.");
1150 return -EINVAL;
1151 }
1152 registered_client = smscore_find_client(coredev, data_type, id);
1153 if (registered_client == client)
1154 return 0;
1155
1156 if (registered_client) {
1157 sms_err("The msg ID already registered to another client.");
1158 return -EEXIST;
1159 }
1160 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1161 if (!listentry) {
1162 sms_err("Can't allocate memory for client id.");
1163 return -ENOMEM;
1164 }
1165 listentry->id = id;
1166 listentry->data_type = data_type;
1167 list_add_locked(&listentry->entry, &client->idlist,
1168 &coredev->clientslock);
1169 return 0;
1170}
1171
1172/**
1173 * creates smsclient object, check that id is taken by another client
1174 *
1175 * @param coredev pointer to a coredev object from clients hotplug
1176 * @param initial_id all messages with this id would be sent to this client
1177 * @param data_type all messages of this type would be sent to this client
1178 * @param onresponse_handler client handler that is called to
1179 * process incoming messages
1180 * @param onremove_handler client handler that is called when device is removed
1181 * @param context client-specific context
1182 * @param client pointer to a value that receives created smsclient object
1183 *
1184 * @return 0 on success, <0 on error.
1185 */
1186int smscore_register_client(struct smscore_device_t *coredev,
1187 struct smsclient_params_t *params,
1188 struct smscore_client_t **client)
1189{
1190 struct smscore_client_t *newclient;
1191 /* check that no other channel with same parameters exists */
1192 if (smscore_find_client(coredev, params->data_type,
1193 params->initial_id)) {
1194 sms_err("Client already exist.");
1195 return -EEXIST;
1196 }
1197
1198 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1199 if (!newclient) {
1200 sms_err("Failed to allocate memory for client.");
1201 return -ENOMEM;
1202 }
1203
1204 INIT_LIST_HEAD(&newclient->idlist);
1205 newclient->coredev = coredev;
1206 newclient->onresponse_handler = params->onresponse_handler;
1207 newclient->onremove_handler = params->onremove_handler;
1208 newclient->context = params->context;
1209 list_add_locked(&newclient->entry, &coredev->clients,
1210 &coredev->clientslock);
1211 smscore_validate_client(coredev, newclient, params->data_type,
1212 params->initial_id);
1213 *client = newclient;
1214 sms_debug("%p %d %d", params->context, params->data_type,
1215 params->initial_id);
1216
1217 return 0;
1218}
1219EXPORT_SYMBOL_GPL(smscore_register_client);
1220
1221/**
1222 * frees smsclient object and all subclients associated with it
1223 *
1224 * @param client pointer to smsclient object returned by
1225 * smscore_register_client
1226 *
1227 */
1228void smscore_unregister_client(struct smscore_client_t *client)
1229{
1230 struct smscore_device_t *coredev = client->coredev;
1231 unsigned long flags;
1232
1233 spin_lock_irqsave(&coredev->clientslock, flags);
1234
1235
1236 while (!list_empty(&client->idlist)) {
1237 struct smscore_idlist_t *identry =
1238 (struct smscore_idlist_t *) client->idlist.next;
1239 list_del(&identry->entry);
1240 kfree(identry);
1241 }
1242
1243 sms_info("%p", client->context);
1244
1245 list_del(&client->entry);
1246 kfree(client);
1247
1248 spin_unlock_irqrestore(&coredev->clientslock, flags);
1249}
1250EXPORT_SYMBOL_GPL(smscore_unregister_client);
1251
1252/**
1253 * verifies that source id is not taken by another client,
1254 * calls device handler to send requests to the device
1255 *
1256 * @param client pointer to smsclient object returned by
1257 * smscore_register_client
1258 * @param buffer pointer to a request buffer
1259 * @param size size (in bytes) of request buffer
1260 *
1261 * @return 0 on success, <0 on error.
1262 */
1263int smsclient_sendrequest(struct smscore_client_t *client,
1264 void *buffer, size_t size)
1265{
1266 struct smscore_device_t *coredev;
1267 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1268 int rc;
1269
1270 if (client == NULL) {
1271 sms_err("Got NULL client");
1272 return -EINVAL;
1273 }
1274
1275 coredev = client->coredev;
1276
1277 /* check that no other channel with same id exists */
1278 if (coredev == NULL) {
1279 sms_err("Got NULL coredev");
1280 return -EINVAL;
1281 }
1282
1283 rc = smscore_validate_client(client->coredev, client, 0,
1284 phdr->msgSrcId);
1285 if (rc < 0)
1286 return rc;
1287
1288 return coredev->sendrequest_handler(coredev->context, buffer, size);
1289}
1290EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1291
1292
1293/* old GPIO managements implementation */
1294int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1295 struct smscore_config_gpio *pinconfig)
1296{
1297 struct {
1298 struct SmsMsgHdr_ST hdr;
1299 u32 data[6];
1300 } msg;
1301
1302 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1303 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1304 msg.hdr.msgDstId = HIF_TASK;
1305 msg.hdr.msgFlags = 0;
1306 msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1307 msg.hdr.msgLength = sizeof(msg);
1308
1309 msg.data[0] = pin;
1310 msg.data[1] = pinconfig->pullupdown;
1311
1312 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1313 msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1314
1315 switch (pinconfig->outputdriving) {
1316 case SMS_GPIO_OUTPUTDRIVING_16mA:
1317 msg.data[3] = 7; /* Nova - 16mA */
1318 break;
1319 case SMS_GPIO_OUTPUTDRIVING_12mA:
1320 msg.data[3] = 5; /* Nova - 11mA */
1321 break;
1322 case SMS_GPIO_OUTPUTDRIVING_8mA:
1323 msg.data[3] = 3; /* Nova - 7mA */
1324 break;
1325 case SMS_GPIO_OUTPUTDRIVING_4mA:
1326 default:
1327 msg.data[3] = 2; /* Nova - 4mA */
1328 break;
1329 }
1330
1331 msg.data[4] = pinconfig->direction;
1332 msg.data[5] = 0;
1333 } else /* TODO: SMS_DEVICE_FAMILY1 */
1334 return -EINVAL;
1335
1336 return coredev->sendrequest_handler(coredev->context,
1337 &msg, sizeof(msg));
1338}
1339
1340int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1341{
1342 struct {
1343 struct SmsMsgHdr_ST hdr;
1344 u32 data[3];
1345 } msg;
1346
1347 if (pin > MAX_GPIO_PIN_NUMBER)
1348 return -EINVAL;
1349
1350 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1351 msg.hdr.msgDstId = HIF_TASK;
1352 msg.hdr.msgFlags = 0;
1353 msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1354 msg.hdr.msgLength = sizeof(msg);
1355
1356 msg.data[0] = pin;
1357 msg.data[1] = level ? 1 : 0;
1358 msg.data[2] = 0;
1359
1360 return coredev->sendrequest_handler(coredev->context,
1361 &msg, sizeof(msg));
1362}
1363
1364/* new GPIO management implementation */
1365static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1366 u32 *pGroupNum, u32 *pGroupCfg) {
1367
1368 *pGroupCfg = 1;
1369
1370 if (PinNum <= 1) {
1371 *pTranslatedPinNum = 0;
1372 *pGroupNum = 9;
1373 *pGroupCfg = 2;
1374 } else if (PinNum >= 2 && PinNum <= 6) {
1375 *pTranslatedPinNum = 2;
1376 *pGroupNum = 0;
1377 *pGroupCfg = 2;
1378 } else if (PinNum >= 7 && PinNum <= 11) {
1379 *pTranslatedPinNum = 7;
1380 *pGroupNum = 1;
1381 } else if (PinNum >= 12 && PinNum <= 15) {
1382 *pTranslatedPinNum = 12;
1383 *pGroupNum = 2;
1384 *pGroupCfg = 3;
1385 } else if (PinNum == 16) {
1386 *pTranslatedPinNum = 16;
1387 *pGroupNum = 23;
1388 } else if (PinNum >= 17 && PinNum <= 24) {
1389 *pTranslatedPinNum = 17;
1390 *pGroupNum = 3;
1391 } else if (PinNum == 25) {
1392 *pTranslatedPinNum = 25;
1393 *pGroupNum = 6;
1394 } else if (PinNum >= 26 && PinNum <= 28) {
1395 *pTranslatedPinNum = 26;
1396 *pGroupNum = 4;
1397 } else if (PinNum == 29) {
1398 *pTranslatedPinNum = 29;
1399 *pGroupNum = 5;
1400 *pGroupCfg = 2;
1401 } else if (PinNum == 30) {
1402 *pTranslatedPinNum = 30;
1403 *pGroupNum = 8;
1404 } else if (PinNum == 31) {
1405 *pTranslatedPinNum = 31;
1406 *pGroupNum = 17;
1407 } else
1408 return -1;
1409
1410 *pGroupCfg <<= 24;
1411
1412 return 0;
1413}
1414
1415int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1416 struct smscore_gpio_config *pGpioConfig) {
1417
1418 u32 totalLen;
1419 u32 TranslatedPinNum = 0;
1420 u32 GroupNum = 0;
1421 u32 ElectricChar;
1422 u32 groupCfg;
1423 void *buffer;
1424 int rc;
1425
1426 struct SetGpioMsg {
1427 struct SmsMsgHdr_ST xMsgHeader;
1428 u32 msgData[6];
1429 } *pMsg;
1430
1431
1432 if (PinNum > MAX_GPIO_PIN_NUMBER)
1433 return -EINVAL;
1434
1435 if (pGpioConfig == NULL)
1436 return -EINVAL;
1437
1438 totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1439
1440 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1441 GFP_KERNEL | GFP_DMA);
1442 if (!buffer)
1443 return -ENOMEM;
1444
1445 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1446
1447 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1448 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1449 pMsg->xMsgHeader.msgFlags = 0;
1450 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1451 pMsg->msgData[0] = PinNum;
1452
1453 if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1454 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1455 if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
1456 &groupCfg) != 0) {
1457 rc = -EINVAL;
1458 goto free;
1459 }
1460
1461 pMsg->msgData[1] = TranslatedPinNum;
1462 pMsg->msgData[2] = GroupNum;
1463 ElectricChar = (pGpioConfig->PullUpDown)
1464 | (pGpioConfig->InputCharacteristics << 2)
1465 | (pGpioConfig->OutputSlewRate << 3)
1466 | (pGpioConfig->OutputDriving << 4);
1467 pMsg->msgData[3] = ElectricChar;
1468 pMsg->msgData[4] = pGpioConfig->Direction;
1469 pMsg->msgData[5] = groupCfg;
1470 } else {
1471 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1472 pMsg->msgData[1] = pGpioConfig->PullUpDown;
1473 pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
1474 pMsg->msgData[3] = pGpioConfig->OutputDriving;
1475 pMsg->msgData[4] = pGpioConfig->Direction;
1476 pMsg->msgData[5] = 0;
1477 }
1478
1479 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1480 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1481 &coredev->gpio_configuration_done);
1482
1483 if (rc != 0) {
1484 if (rc == -ETIME)
1485 sms_err("smscore_gpio_configure timeout");
1486 else
1487 sms_err("smscore_gpio_configure error");
1488 }
1489free:
1490 kfree(buffer);
1491
1492 return rc;
1493}
1494
1495int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1496 u8 NewLevel) {
1497
1498 u32 totalLen;
1499 int rc;
1500 void *buffer;
1501
1502 struct SetGpioMsg {
1503 struct SmsMsgHdr_ST xMsgHeader;
1504 u32 msgData[3]; /* keep it 3 ! */
1505 } *pMsg;
1506
1507 if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
1508 return -EINVAL;
1509
1510 totalLen = sizeof(struct SmsMsgHdr_ST) +
1511 (3 * sizeof(u32)); /* keep it 3 ! */
1512
1513 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1514 GFP_KERNEL | GFP_DMA);
1515 if (!buffer)
1516 return -ENOMEM;
1517
1518 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1519
1520 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1521 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1522 pMsg->xMsgHeader.msgFlags = 0;
1523 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1524 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1525 pMsg->msgData[0] = PinNum;
1526 pMsg->msgData[1] = NewLevel;
1527
1528 /* Send message to SMS */
1529 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1530 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1531 &coredev->gpio_set_level_done);
1532
1533 if (rc != 0) {
1534 if (rc == -ETIME)
1535 sms_err("smscore_gpio_set_level timeout");
1536 else
1537 sms_err("smscore_gpio_set_level error");
1538 }
1539 kfree(buffer);
1540
1541 return rc;
1542}
1543
1544int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1545 u8 *level) {
1546
1547 u32 totalLen;
1548 int rc;
1549 void *buffer;
1550
1551 struct SetGpioMsg {
1552 struct SmsMsgHdr_ST xMsgHeader;
1553 u32 msgData[2];
1554 } *pMsg;
1555
1556
1557 if (PinNum > MAX_GPIO_PIN_NUMBER)
1558 return -EINVAL;
1559
1560 totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1561
1562 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1563 GFP_KERNEL | GFP_DMA);
1564 if (!buffer)
1565 return -ENOMEM;
1566
1567 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1568
1569 pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1570 pMsg->xMsgHeader.msgDstId = HIF_TASK;
1571 pMsg->xMsgHeader.msgFlags = 0;
1572 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
1573 pMsg->xMsgHeader.msgLength = (u16) totalLen;
1574 pMsg->msgData[0] = PinNum;
1575 pMsg->msgData[1] = 0;
1576
1577 /* Send message to SMS */
1578 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1579 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1580 &coredev->gpio_get_level_done);
1581
1582 if (rc != 0) {
1583 if (rc == -ETIME)
1584 sms_err("smscore_gpio_get_level timeout");
1585 else
1586 sms_err("smscore_gpio_get_level error");
1587 }
1588 kfree(buffer);
1589
1590 /* Its a race between other gpio_get_level() and the copy of the single
1591 * global 'coredev->gpio_get_res' to the function's variable 'level'
1592 */
1593 *level = coredev->gpio_get_res;
1594
1595 return rc;
1596}
1597
1598static int __init smscore_module_init(void)
1599{
1600 int rc = 0;
1601
1602 INIT_LIST_HEAD(&g_smscore_notifyees);
1603 INIT_LIST_HEAD(&g_smscore_devices);
1604 kmutex_init(&g_smscore_deviceslock);
1605
1606 INIT_LIST_HEAD(&g_smscore_registry);
1607 kmutex_init(&g_smscore_registrylock);
1608
1609 return rc;
1610}
1611
1612static void __exit smscore_module_exit(void)
1613{
1614 kmutex_lock(&g_smscore_deviceslock);
1615 while (!list_empty(&g_smscore_notifyees)) {
1616 struct smscore_device_notifyee_t *notifyee =
1617 (struct smscore_device_notifyee_t *)
1618 g_smscore_notifyees.next;
1619
1620 list_del(&notifyee->entry);
1621 kfree(notifyee);
1622 }
1623 kmutex_unlock(&g_smscore_deviceslock);
1624
1625 kmutex_lock(&g_smscore_registrylock);
1626 while (!list_empty(&g_smscore_registry)) {
1627 struct smscore_registry_entry_t *entry =
1628 (struct smscore_registry_entry_t *)
1629 g_smscore_registry.next;
1630
1631 list_del(&entry->entry);
1632 kfree(entry);
1633 }
1634 kmutex_unlock(&g_smscore_registrylock);
1635
1636 sms_debug("");
1637}
1638
1639module_init(smscore_module_init);
1640module_exit(smscore_module_exit);
1641
1642MODULE_DESCRIPTION("Siano MDTV Core module");
1643MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1644MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
new file mode 100644
index 00000000000..c592ae09039
--- /dev/null
+++ b/drivers/media/dvb/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/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
new file mode 100644
index 00000000000..37c594f8278
--- /dev/null
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -0,0 +1,962 @@
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 /* todo: save freq/band instead whole struct */
53 struct dvb_frontend_parameters fe_params;
54
55 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
56 int event_fe_state;
57 int event_unc_state;
58};
59
60static struct list_head g_smsdvb_clients;
61static struct mutex g_smsdvb_clientslock;
62
63static int sms_dbg;
64module_param_named(debug, sms_dbg, int, 0644);
65MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
66
67/* Events that may come from DVB v3 adapter */
68static void sms_board_dvb3_event(struct smsdvb_client_t *client,
69 enum SMS_DVB3_EVENTS event) {
70
71 struct smscore_device_t *coredev = client->coredev;
72 switch (event) {
73 case DVB3_EVENT_INIT:
74 sms_debug("DVB3_EVENT_INIT");
75 sms_board_event(coredev, BOARD_EVENT_BIND);
76 break;
77 case DVB3_EVENT_SLEEP:
78 sms_debug("DVB3_EVENT_SLEEP");
79 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
80 break;
81 case DVB3_EVENT_HOTPLUG:
82 sms_debug("DVB3_EVENT_HOTPLUG");
83 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
84 break;
85 case DVB3_EVENT_FE_LOCK:
86 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
87 client->event_fe_state = DVB3_EVENT_FE_LOCK;
88 sms_debug("DVB3_EVENT_FE_LOCK");
89 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
90 }
91 break;
92 case DVB3_EVENT_FE_UNLOCK:
93 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
94 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
95 sms_debug("DVB3_EVENT_FE_UNLOCK");
96 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
97 }
98 break;
99 case DVB3_EVENT_UNC_OK:
100 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
101 client->event_unc_state = DVB3_EVENT_UNC_OK;
102 sms_debug("DVB3_EVENT_UNC_OK");
103 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
104 }
105 break;
106 case DVB3_EVENT_UNC_ERR:
107 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
108 client->event_unc_state = DVB3_EVENT_UNC_ERR;
109 sms_debug("DVB3_EVENT_UNC_ERR");
110 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
111 }
112 break;
113
114 default:
115 sms_err("Unknown dvb3 api event");
116 break;
117 }
118}
119
120
121static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
122 struct SMSHOSTLIB_STATISTICS_ST *p)
123{
124 if (sms_dbg & 2) {
125 printk(KERN_DEBUG "Reserved = %d", p->Reserved);
126 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
127 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
128 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
129 printk(KERN_DEBUG "SNR = %d", p->SNR);
130 printk(KERN_DEBUG "BER = %d", p->BER);
131 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
132 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
133 printk(KERN_DEBUG "MFER = %d", p->MFER);
134 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
135 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
136 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
137 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
138 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
139 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
140 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
141 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
142 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
143 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
144 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
145 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
146 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
147 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
148 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
149 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
150 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
151 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
152 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
153 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
154 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
155 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
156 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
157 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
158 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
159 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
160 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
161 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
162 printk(KERN_DEBUG "CellId = %d", p->CellId);
163 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
164 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
165 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
166 }
167
168 pReceptionData->IsDemodLocked = p->IsDemodLocked;
169
170 pReceptionData->SNR = p->SNR;
171 pReceptionData->BER = p->BER;
172 pReceptionData->BERErrorCount = p->BERErrorCount;
173 pReceptionData->InBandPwr = p->InBandPwr;
174 pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
175};
176
177
178static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
179 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
180{
181 int i;
182
183 if (sms_dbg & 2) {
184 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
185 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
186 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
187 printk(KERN_DEBUG "SNR = %d", p->SNR);
188 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
189 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
190 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
191 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
192 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
193 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
194 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
195 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
196 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
197 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
198 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
199 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
200
201 for (i = 0; i < 3; i++) {
202 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
203 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
204 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
205 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
206 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
207 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
208 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
209 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
210 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
211 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
212 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
213 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
214 }
215 }
216
217 pReceptionData->IsDemodLocked = p->IsDemodLocked;
218
219 pReceptionData->SNR = p->SNR;
220 pReceptionData->InBandPwr = p->InBandPwr;
221
222 pReceptionData->ErrorTSPackets = 0;
223 pReceptionData->BER = 0;
224 pReceptionData->BERErrorCount = 0;
225 for (i = 0; i < 3; i++) {
226 pReceptionData->BER += p->LayerInfo[i].BER;
227 pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
228 pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
229 }
230}
231
232static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
233{
234 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
235 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
236 + cb->offset);
237 u32 *pMsgData = (u32 *) phdr + 1;
238 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
239 bool is_status_update = false;
240
241 smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
242
243 switch (phdr->msgType) {
244 case MSG_SMS_DVBT_BDA_DATA:
245 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
246 cb->size - sizeof(struct SmsMsgHdr_ST));
247 break;
248
249 case MSG_SMS_RF_TUNE_RES:
250 case MSG_SMS_ISDBT_TUNE_RES:
251 complete(&client->tune_done);
252 break;
253
254 case MSG_SMS_SIGNAL_DETECTED_IND:
255 sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
256 client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
257 is_status_update = true;
258 break;
259
260 case MSG_SMS_NO_SIGNAL_IND:
261 sms_info("MSG_SMS_NO_SIGNAL_IND");
262 client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
263 is_status_update = true;
264 break;
265
266 case MSG_SMS_TRANSMISSION_IND: {
267 sms_info("MSG_SMS_TRANSMISSION_IND");
268
269 pMsgData++;
270 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
271 sizeof(struct TRANSMISSION_STATISTICS_S));
272
273 /* Mo need to correct guard interval
274 * (as opposed to old statistics message).
275 */
276 CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
277 CORRECT_STAT_TRANSMISSON_MODE(
278 client->sms_stat_dvb.TransmissionData);
279 is_status_update = true;
280 break;
281 }
282 case MSG_SMS_HO_PER_SLICES_IND: {
283 struct RECEPTION_STATISTICS_S *pReceptionData =
284 &client->sms_stat_dvb.ReceptionData;
285 struct SRVM_SIGNAL_STATUS_S SignalStatusData;
286
287 /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
288 pMsgData++;
289 SignalStatusData.result = pMsgData[0];
290 SignalStatusData.snr = pMsgData[1];
291 SignalStatusData.inBandPower = (s32) pMsgData[2];
292 SignalStatusData.tsPackets = pMsgData[3];
293 SignalStatusData.etsPackets = pMsgData[4];
294 SignalStatusData.constellation = pMsgData[5];
295 SignalStatusData.hpCode = pMsgData[6];
296 SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
297 SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
298 SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
299 SignalStatusData.reason = pMsgData[10];
300 SignalStatusData.requestId = pMsgData[11];
301 pReceptionData->IsRfLocked = pMsgData[16];
302 pReceptionData->IsDemodLocked = pMsgData[17];
303 pReceptionData->ModemState = pMsgData[12];
304 pReceptionData->SNR = pMsgData[1];
305 pReceptionData->BER = pMsgData[13];
306 pReceptionData->RSSI = pMsgData[14];
307 CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
308
309 pReceptionData->InBandPwr = (s32) pMsgData[2];
310 pReceptionData->CarrierOffset = (s32) pMsgData[15];
311 pReceptionData->TotalTSPackets = pMsgData[3];
312 pReceptionData->ErrorTSPackets = pMsgData[4];
313
314 /* TS PER */
315 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
316 > 0) {
317 pReceptionData->TS_PER = (SignalStatusData.etsPackets
318 * 100) / (SignalStatusData.tsPackets
319 + SignalStatusData.etsPackets);
320 } else {
321 pReceptionData->TS_PER = 0;
322 }
323
324 pReceptionData->BERBitCount = pMsgData[18];
325 pReceptionData->BERErrorCount = pMsgData[19];
326
327 pReceptionData->MRC_SNR = pMsgData[20];
328 pReceptionData->MRC_InBandPwr = pMsgData[21];
329 pReceptionData->MRC_RSSI = pMsgData[22];
330
331 is_status_update = true;
332 break;
333 }
334 case MSG_SMS_GET_STATISTICS_RES: {
335 union {
336 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
337 struct SmsMsgStatisticsInfo_ST dvb;
338 } *p = (void *) (phdr + 1);
339 struct RECEPTION_STATISTICS_S *pReceptionData =
340 &client->sms_stat_dvb.ReceptionData;
341
342 sms_info("MSG_SMS_GET_STATISTICS_RES");
343
344 is_status_update = true;
345
346 switch (smscore_get_device_mode(client->coredev)) {
347 case DEVICE_MODE_ISDBT:
348 case DEVICE_MODE_ISDBT_BDA:
349 smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
350 break;
351 default:
352 smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
353 }
354 if (!pReceptionData->IsDemodLocked) {
355 pReceptionData->SNR = 0;
356 pReceptionData->BER = 0;
357 pReceptionData->BERErrorCount = 0;
358 pReceptionData->InBandPwr = 0;
359 pReceptionData->ErrorTSPackets = 0;
360 }
361
362 complete(&client->tune_done);
363 break;
364 }
365 default:
366 sms_info("Unhandled message %d", phdr->msgType);
367
368 }
369 smscore_putbuffer(client->coredev, cb);
370
371 if (is_status_update) {
372 if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
373 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
374 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
375 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
376 if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
377 == 0)
378 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
379 else
380 sms_board_dvb3_event(client,
381 DVB3_EVENT_UNC_ERR);
382
383 } else {
384 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
385 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
386 else
387 client->fe_status = 0;
388 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
389 }
390 }
391
392 return 0;
393}
394
395static void smsdvb_unregister_client(struct smsdvb_client_t *client)
396{
397 /* must be called under clientslock */
398
399 list_del(&client->entry);
400
401 smscore_unregister_client(client->smsclient);
402 dvb_unregister_frontend(&client->frontend);
403 dvb_dmxdev_release(&client->dmxdev);
404 dvb_dmx_release(&client->demux);
405 dvb_unregister_adapter(&client->adapter);
406 kfree(client);
407}
408
409static void smsdvb_onremove(void *context)
410{
411 kmutex_lock(&g_smsdvb_clientslock);
412
413 smsdvb_unregister_client((struct smsdvb_client_t *) context);
414
415 kmutex_unlock(&g_smsdvb_clientslock);
416}
417
418static int smsdvb_start_feed(struct dvb_demux_feed *feed)
419{
420 struct smsdvb_client_t *client =
421 container_of(feed->demux, struct smsdvb_client_t, demux);
422 struct SmsMsgData_ST PidMsg;
423
424 sms_debug("add pid %d(%x)",
425 feed->pid, feed->pid);
426
427 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
428 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
429 PidMsg.xMsgHeader.msgFlags = 0;
430 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
431 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
432 PidMsg.msgData[0] = feed->pid;
433
434 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
435 return smsclient_sendrequest(client->smsclient,
436 &PidMsg, sizeof(PidMsg));
437}
438
439static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
440{
441 struct smsdvb_client_t *client =
442 container_of(feed->demux, struct smsdvb_client_t, demux);
443 struct SmsMsgData_ST PidMsg;
444
445 sms_debug("remove pid %d(%x)",
446 feed->pid, feed->pid);
447
448 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
449 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
450 PidMsg.xMsgHeader.msgFlags = 0;
451 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
452 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
453 PidMsg.msgData[0] = feed->pid;
454
455 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
456 return smsclient_sendrequest(client->smsclient,
457 &PidMsg, sizeof(PidMsg));
458}
459
460static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
461 void *buffer, size_t size,
462 struct completion *completion)
463{
464 int rc;
465
466 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
467 rc = smsclient_sendrequest(client->smsclient, buffer, size);
468 if (rc < 0)
469 return rc;
470
471 return wait_for_completion_timeout(completion,
472 msecs_to_jiffies(2000)) ?
473 0 : -ETIME;
474}
475
476static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
477{
478 int rc;
479 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
480 DVBT_BDA_CONTROL_MSG_ID,
481 HIF_TASK,
482 sizeof(struct SmsMsgHdr_ST), 0 };
483
484 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
485 &client->tune_done);
486
487 return rc;
488}
489
490static inline int led_feedback(struct smsdvb_client_t *client)
491{
492 if (client->fe_status & FE_HAS_LOCK)
493 return sms_board_led_feedback(client->coredev,
494 (client->sms_stat_dvb.ReceptionData.BER
495 == 0) ? SMS_LED_HI : SMS_LED_LO);
496 else
497 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
498}
499
500static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
501{
502 int rc;
503 struct smsdvb_client_t *client;
504 client = container_of(fe, struct smsdvb_client_t, frontend);
505
506 rc = smsdvb_send_statistics_request(client);
507
508 *stat = client->fe_status;
509
510 led_feedback(client);
511
512 return rc;
513}
514
515static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
516{
517 int rc;
518 struct smsdvb_client_t *client;
519 client = container_of(fe, struct smsdvb_client_t, frontend);
520
521 rc = smsdvb_send_statistics_request(client);
522
523 *ber = client->sms_stat_dvb.ReceptionData.BER;
524
525 led_feedback(client);
526
527 return rc;
528}
529
530static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
531{
532 int rc;
533
534 struct smsdvb_client_t *client;
535 client = container_of(fe, struct smsdvb_client_t, frontend);
536
537 rc = smsdvb_send_statistics_request(client);
538
539 if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
540 *strength = 0;
541 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
542 *strength = 100;
543 else
544 *strength =
545 (client->sms_stat_dvb.ReceptionData.InBandPwr
546 + 95) * 3 / 2;
547
548 led_feedback(client);
549
550 return rc;
551}
552
553static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
554{
555 int rc;
556 struct smsdvb_client_t *client;
557 client = container_of(fe, struct smsdvb_client_t, frontend);
558
559 rc = smsdvb_send_statistics_request(client);
560
561 *snr = client->sms_stat_dvb.ReceptionData.SNR;
562
563 led_feedback(client);
564
565 return rc;
566}
567
568static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
569{
570 int rc;
571 struct smsdvb_client_t *client;
572 client = container_of(fe, struct smsdvb_client_t, frontend);
573
574 rc = smsdvb_send_statistics_request(client);
575
576 *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
577
578 led_feedback(client);
579
580 return rc;
581}
582
583static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
584 struct dvb_frontend_tune_settings *tune)
585{
586 sms_debug("");
587
588 tune->min_delay_ms = 400;
589 tune->step_size = 250000;
590 tune->max_drift = 0;
591 return 0;
592}
593
594static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
595 struct dvb_frontend_parameters *p)
596{
597 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
598 struct smsdvb_client_t *client =
599 container_of(fe, struct smsdvb_client_t, frontend);
600
601 struct {
602 struct SmsMsgHdr_ST Msg;
603 u32 Data[3];
604 } Msg;
605
606 int ret;
607
608 client->fe_status = FE_HAS_SIGNAL;
609 client->event_fe_state = -1;
610 client->event_unc_state = -1;
611 fe->dtv_property_cache.delivery_system = SYS_DVBT;
612
613 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
614 Msg.Msg.msgDstId = HIF_TASK;
615 Msg.Msg.msgFlags = 0;
616 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
617 Msg.Msg.msgLength = sizeof(Msg);
618 Msg.Data[0] = c->frequency;
619 Msg.Data[2] = 12000000;
620
621 sms_info("%s: freq %d band %d", __func__, c->frequency,
622 c->bandwidth_hz);
623
624 switch (c->bandwidth_hz / 1000000) {
625 case 8:
626 Msg.Data[1] = BW_8_MHZ;
627 break;
628 case 7:
629 Msg.Data[1] = BW_7_MHZ;
630 break;
631 case 6:
632 Msg.Data[1] = BW_6_MHZ;
633 break;
634 case 0:
635 return -EOPNOTSUPP;
636 default:
637 return -EINVAL;
638 }
639 /* Disable LNA, if any. An error is returned if no LNA is present */
640 ret = sms_board_lna_control(client->coredev, 0);
641 if (ret == 0) {
642 fe_status_t status;
643
644 /* tune with LNA off at first */
645 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
646 &client->tune_done);
647
648 smsdvb_read_status(fe, &status);
649
650 if (status & FE_HAS_LOCK)
651 return ret;
652
653 /* previous tune didn't lock - enable LNA and tune again */
654 sms_board_lna_control(client->coredev, 1);
655 }
656
657 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
658 &client->tune_done);
659}
660
661static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
662 struct dvb_frontend_parameters *p)
663{
664 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
665 struct smsdvb_client_t *client =
666 container_of(fe, struct smsdvb_client_t, frontend);
667
668 struct {
669 struct SmsMsgHdr_ST Msg;
670 u32 Data[4];
671 } Msg;
672
673 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
674
675 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
676 Msg.Msg.msgDstId = HIF_TASK;
677 Msg.Msg.msgFlags = 0;
678 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
679 Msg.Msg.msgLength = sizeof(Msg);
680
681 if (c->isdbt_sb_segment_idx == -1)
682 c->isdbt_sb_segment_idx = 0;
683
684 switch (c->isdbt_sb_segment_count) {
685 case 3:
686 Msg.Data[1] = BW_ISDBT_3SEG;
687 break;
688 case 1:
689 Msg.Data[1] = BW_ISDBT_1SEG;
690 break;
691 case 0: /* AUTO */
692 switch (c->bandwidth_hz / 1000000) {
693 case 8:
694 case 7:
695 c->isdbt_sb_segment_count = 3;
696 Msg.Data[1] = BW_ISDBT_3SEG;
697 break;
698 case 6:
699 c->isdbt_sb_segment_count = 1;
700 Msg.Data[1] = BW_ISDBT_1SEG;
701 break;
702 default: /* Assumes 6 MHZ bw */
703 c->isdbt_sb_segment_count = 1;
704 c->bandwidth_hz = 6000;
705 Msg.Data[1] = BW_ISDBT_1SEG;
706 break;
707 }
708 break;
709 default:
710 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
711 return -EINVAL;
712 }
713
714 Msg.Data[0] = c->frequency;
715 Msg.Data[2] = 12000000;
716 Msg.Data[3] = c->isdbt_sb_segment_idx;
717
718 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
719 c->frequency, c->isdbt_sb_segment_count,
720 c->isdbt_sb_segment_idx);
721
722 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
723 &client->tune_done);
724}
725
726static int smsdvb_set_frontend(struct dvb_frontend *fe,
727 struct dvb_frontend_parameters *fep)
728{
729 struct smsdvb_client_t *client =
730 container_of(fe, struct smsdvb_client_t, frontend);
731 struct smscore_device_t *coredev = client->coredev;
732
733 switch (smscore_get_device_mode(coredev)) {
734 case DEVICE_MODE_DVBT:
735 case DEVICE_MODE_DVBT_BDA:
736 return smsdvb_dvbt_set_frontend(fe, fep);
737 case DEVICE_MODE_ISDBT:
738 case DEVICE_MODE_ISDBT_BDA:
739 return smsdvb_isdbt_set_frontend(fe, fep);
740 default:
741 return -EINVAL;
742 }
743}
744
745static int smsdvb_get_frontend(struct dvb_frontend *fe,
746 struct dvb_frontend_parameters *fep)
747{
748 struct smsdvb_client_t *client =
749 container_of(fe, struct smsdvb_client_t, frontend);
750
751 sms_debug("");
752
753 /* todo: */
754 memcpy(fep, &client->fe_params,
755 sizeof(struct dvb_frontend_parameters));
756
757 return 0;
758}
759
760static int smsdvb_init(struct dvb_frontend *fe)
761{
762 struct smsdvb_client_t *client =
763 container_of(fe, struct smsdvb_client_t, frontend);
764
765 sms_board_power(client->coredev, 1);
766
767 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
768 return 0;
769}
770
771static int smsdvb_sleep(struct dvb_frontend *fe)
772{
773 struct smsdvb_client_t *client =
774 container_of(fe, struct smsdvb_client_t, frontend);
775
776 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
777 sms_board_power(client->coredev, 0);
778
779 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
780
781 return 0;
782}
783
784static void smsdvb_release(struct dvb_frontend *fe)
785{
786 /* do nothing */
787}
788
789static struct dvb_frontend_ops smsdvb_fe_ops = {
790 .info = {
791 .name = "Siano Mobile Digital MDTV Receiver",
792 .type = FE_OFDM,
793 .frequency_min = 44250000,
794 .frequency_max = 867250000,
795 .frequency_stepsize = 250000,
796 .caps = FE_CAN_INVERSION_AUTO |
797 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
798 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
799 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
800 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
801 FE_CAN_GUARD_INTERVAL_AUTO |
802 FE_CAN_RECOVER |
803 FE_CAN_HIERARCHY_AUTO,
804 },
805
806 .release = smsdvb_release,
807
808 .set_frontend = smsdvb_set_frontend,
809 .get_frontend = smsdvb_get_frontend,
810 .get_tune_settings = smsdvb_get_tune_settings,
811
812 .read_status = smsdvb_read_status,
813 .read_ber = smsdvb_read_ber,
814 .read_signal_strength = smsdvb_read_signal_strength,
815 .read_snr = smsdvb_read_snr,
816 .read_ucblocks = smsdvb_read_ucblocks,
817
818 .init = smsdvb_init,
819 .sleep = smsdvb_sleep,
820};
821
822static int smsdvb_hotplug(struct smscore_device_t *coredev,
823 struct device *device, int arrival)
824{
825 struct smsclient_params_t params;
826 struct smsdvb_client_t *client;
827 int rc;
828
829 /* device removal handled by onremove callback */
830 if (!arrival)
831 return 0;
832 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
833 if (!client) {
834 sms_err("kmalloc() failed");
835 return -ENOMEM;
836 }
837
838 /* register dvb adapter */
839 rc = dvb_register_adapter(&client->adapter,
840 sms_get_board(
841 smscore_get_board_id(coredev))->name,
842 THIS_MODULE, device, adapter_nr);
843 if (rc < 0) {
844 sms_err("dvb_register_adapter() failed %d", rc);
845 goto adapter_error;
846 }
847
848 /* init dvb demux */
849 client->demux.dmx.capabilities = DMX_TS_FILTERING;
850 client->demux.filternum = 32; /* todo: nova ??? */
851 client->demux.feednum = 32;
852 client->demux.start_feed = smsdvb_start_feed;
853 client->demux.stop_feed = smsdvb_stop_feed;
854
855 rc = dvb_dmx_init(&client->demux);
856 if (rc < 0) {
857 sms_err("dvb_dmx_init failed %d", rc);
858 goto dvbdmx_error;
859 }
860
861 /* init dmxdev */
862 client->dmxdev.filternum = 32;
863 client->dmxdev.demux = &client->demux.dmx;
864 client->dmxdev.capabilities = 0;
865
866 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
867 if (rc < 0) {
868 sms_err("dvb_dmxdev_init failed %d", rc);
869 goto dmxdev_error;
870 }
871
872 /* init and register frontend */
873 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
874 sizeof(struct dvb_frontend_ops));
875
876 rc = dvb_register_frontend(&client->adapter, &client->frontend);
877 if (rc < 0) {
878 sms_err("frontend registration failed %d", rc);
879 goto frontend_error;
880 }
881
882 params.initial_id = 1;
883 params.data_type = MSG_SMS_DVBT_BDA_DATA;
884 params.onresponse_handler = smsdvb_onresponse;
885 params.onremove_handler = smsdvb_onremove;
886 params.context = client;
887
888 rc = smscore_register_client(coredev, &params, &client->smsclient);
889 if (rc < 0) {
890 sms_err("smscore_register_client() failed %d", rc);
891 goto client_error;
892 }
893
894 client->coredev = coredev;
895
896 init_completion(&client->tune_done);
897
898 kmutex_lock(&g_smsdvb_clientslock);
899
900 list_add(&client->entry, &g_smsdvb_clients);
901
902 kmutex_unlock(&g_smsdvb_clientslock);
903
904 client->event_fe_state = -1;
905 client->event_unc_state = -1;
906 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
907
908 sms_info("success");
909 sms_board_setup(coredev);
910
911 return 0;
912
913client_error:
914 dvb_unregister_frontend(&client->frontend);
915
916frontend_error:
917 dvb_dmxdev_release(&client->dmxdev);
918
919dmxdev_error:
920 dvb_dmx_release(&client->demux);
921
922dvbdmx_error:
923 dvb_unregister_adapter(&client->adapter);
924
925adapter_error:
926 kfree(client);
927 return rc;
928}
929
930static int __init smsdvb_module_init(void)
931{
932 int rc;
933
934 INIT_LIST_HEAD(&g_smsdvb_clients);
935 kmutex_init(&g_smsdvb_clientslock);
936
937 rc = smscore_register_hotplug(smsdvb_hotplug);
938
939 sms_debug("");
940
941 return rc;
942}
943
944static void __exit smsdvb_module_exit(void)
945{
946 smscore_unregister_hotplug(smsdvb_hotplug);
947
948 kmutex_lock(&g_smsdvb_clientslock);
949
950 while (!list_empty(&g_smsdvb_clients))
951 smsdvb_unregister_client(
952 (struct smsdvb_client_t *) g_smsdvb_clients.next);
953
954 kmutex_unlock(&g_smsdvb_clientslock);
955}
956
957module_init(smsdvb_module_init);
958module_exit(smsdvb_module_exit);
959
960MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
961MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
962MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c
new file mode 100644
index 00000000000..457b6d02ef8
--- /dev/null
+++ b/drivers/media/dvb/siano/smsendian.c
@@ -0,0 +1,102 @@
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 <asm/byteorder.h>
23
24#include "smsendian.h"
25#include "smscoreapi.h"
26
27void smsendian_handle_tx_message(void *buffer)
28{
29#ifdef __BIG_ENDIAN
30 struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
31 int i;
32 int msgWords;
33
34 switch (msg->xMsgHeader.msgType) {
35 case MSG_SMS_DATA_DOWNLOAD_REQ:
36 {
37 msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
38 break;
39 }
40
41 default:
42 msgWords = (msg->xMsgHeader.msgLength -
43 sizeof(struct SmsMsgHdr_ST))/4;
44
45 for (i = 0; i < msgWords; i++)
46 msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
47
48 break;
49 }
50#endif /* __BIG_ENDIAN */
51}
52EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
53
54void smsendian_handle_rx_message(void *buffer)
55{
56#ifdef __BIG_ENDIAN
57 struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
58 int i;
59 int msgWords;
60
61 switch (msg->xMsgHeader.msgType) {
62 case MSG_SMS_GET_VERSION_EX_RES:
63 {
64 struct SmsVersionRes_ST *ver =
65 (struct SmsVersionRes_ST *) msg;
66 ver->ChipModel = le16_to_cpu(ver->ChipModel);
67 break;
68 }
69
70 case MSG_SMS_DVBT_BDA_DATA:
71 case MSG_SMS_DAB_CHANNEL:
72 case MSG_SMS_DATA_MSG:
73 {
74 break;
75 }
76
77 default:
78 {
79 msgWords = (msg->xMsgHeader.msgLength -
80 sizeof(struct SmsMsgHdr_ST))/4;
81
82 for (i = 0; i < msgWords; i++)
83 msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
84
85 break;
86 }
87 }
88#endif /* __BIG_ENDIAN */
89}
90EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
91
92void smsendian_handle_message_header(void *msg)
93{
94#ifdef __BIG_ENDIAN
95 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
96
97 phdr->msgType = le16_to_cpu(phdr->msgType);
98 phdr->msgLength = le16_to_cpu(phdr->msgLength);
99 phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
100#endif /* __BIG_ENDIAN */
101}
102EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h
new file mode 100644
index 00000000000..1624d6fd367
--- /dev/null
+++ b/drivers/media/dvb/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/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
new file mode 100644
index 00000000000..37bc5c4b8ad
--- /dev/null
+++ b/drivers/media/dvb/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/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
new file mode 100644
index 00000000000..ae92b3a8587
--- /dev/null
+++ b/drivers/media/dvb/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
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
new file mode 100644
index 00000000000..e57d38b0197
--- /dev/null
+++ b/drivers/media/dvb/siano/smssdio.c
@@ -0,0 +1,364 @@
1/*
2 * smssdio.c - Siano 1xxx SDIO interface driver
3 *
4 * Copyright 2008 Pierre Ossman
5 *
6 * Based on code by Siano Mobile Silicon, Inc.,
7 * Copyright (C) 2006-2008, Uri Shkolnik
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 *
15 * This hardware is a bit odd in that all transfers should be done
16 * to/from the SMSSDIO_DATA register, yet the "increase address" bit
17 * always needs to be set.
18 *
19 * Also, buffers from the card are always aligned to 128 byte
20 * boundaries.
21 */
22
23/*
24 * General cleanup notes:
25 *
26 * - only typedefs should be name *_t
27 *
28 * - use ERR_PTR and friends for smscore_register_device()
29 *
30 * - smscore_getbuffer should zero fields
31 *
32 * Fix stop command
33 */
34
35#include <linux/moduleparam.h>
36#include <linux/slab.h>
37#include <linux/firmware.h>
38#include <linux/delay.h>
39#include <linux/mmc/card.h>
40#include <linux/mmc/sdio_func.h>
41#include <linux/mmc/sdio_ids.h>
42
43#include "smscoreapi.h"
44#include "sms-cards.h"
45
46/* Registers */
47
48#define SMSSDIO_DATA 0x00
49#define SMSSDIO_INT 0x04
50#define SMSSDIO_BLOCK_SIZE 128
51
52static const struct sdio_device_id smssdio_ids[] __devinitconst = {
53 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
54 .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
55 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
56 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
57 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
58 .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
59 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
60 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
61 {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
62 .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
63 { /* end: all zeroes */ },
64};
65
66MODULE_DEVICE_TABLE(sdio, smssdio_ids);
67
68struct smssdio_device {
69 struct sdio_func *func;
70
71 struct smscore_device_t *coredev;
72
73 struct smscore_buffer_t *split_cb;
74};
75
76/*******************************************************************/
77/* Siano core callbacks */
78/*******************************************************************/
79
80static int smssdio_sendrequest(void *context, void *buffer, size_t size)
81{
82 int ret = 0;
83 struct smssdio_device *smsdev;
84
85 smsdev = context;
86
87 sdio_claim_host(smsdev->func);
88
89 while (size >= smsdev->func->cur_blksize) {
90 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
91 buffer, smsdev->func->cur_blksize);
92 if (ret)
93 goto out;
94
95 buffer += smsdev->func->cur_blksize;
96 size -= smsdev->func->cur_blksize;
97 }
98
99 if (size) {
100 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
101 buffer, size);
102 }
103
104out:
105 sdio_release_host(smsdev->func);
106
107 return ret;
108}
109
110/*******************************************************************/
111/* SDIO callbacks */
112/*******************************************************************/
113
114static void smssdio_interrupt(struct sdio_func *func)
115{
116 int ret, isr;
117
118 struct smssdio_device *smsdev;
119 struct smscore_buffer_t *cb;
120 struct SmsMsgHdr_ST *hdr;
121 size_t size;
122
123 smsdev = sdio_get_drvdata(func);
124
125 /*
126 * The interrupt register has no defined meaning. It is just
127 * a way of turning of the level triggered interrupt.
128 */
129 isr = sdio_readb(func, SMSSDIO_INT, &ret);
130 if (ret) {
131 sms_err("Unable to read interrupt register!\n");
132 return;
133 }
134
135 if (smsdev->split_cb == NULL) {
136 cb = smscore_getbuffer(smsdev->coredev);
137 if (!cb) {
138 sms_err("Unable to allocate data buffer!\n");
139 return;
140 }
141
142 ret = sdio_memcpy_fromio(smsdev->func,
143 cb->p,
144 SMSSDIO_DATA,
145 SMSSDIO_BLOCK_SIZE);
146 if (ret) {
147 sms_err("Error %d reading initial block!\n", ret);
148 return;
149 }
150
151 hdr = cb->p;
152
153 if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
154 smsdev->split_cb = cb;
155 return;
156 }
157
158 if (hdr->msgLength > smsdev->func->cur_blksize)
159 size = hdr->msgLength - smsdev->func->cur_blksize;
160 else
161 size = 0;
162 } else {
163 cb = smsdev->split_cb;
164 hdr = cb->p;
165
166 size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
167
168 smsdev->split_cb = NULL;
169 }
170
171 if (size) {
172 void *buffer;
173
174 buffer = cb->p + (hdr->msgLength - size);
175 size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
176
177 BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
178
179 /*
180 * First attempt to transfer all of it in one go...
181 */
182 ret = sdio_memcpy_fromio(smsdev->func,
183 buffer,
184 SMSSDIO_DATA,
185 size);
186 if (ret && ret != -EINVAL) {
187 smscore_putbuffer(smsdev->coredev, cb);
188 sms_err("Error %d reading data from card!\n", ret);
189 return;
190 }
191
192 /*
193 * ..then fall back to one block at a time if that is
194 * not possible...
195 *
196 * (we have to do this manually because of the
197 * problem with the "increase address" bit)
198 */
199 if (ret == -EINVAL) {
200 while (size) {
201 ret = sdio_memcpy_fromio(smsdev->func,
202 buffer, SMSSDIO_DATA,
203 smsdev->func->cur_blksize);
204 if (ret) {
205 smscore_putbuffer(smsdev->coredev, cb);
206 sms_err("Error %d reading "
207 "data from card!\n", ret);
208 return;
209 }
210
211 buffer += smsdev->func->cur_blksize;
212 if (size > smsdev->func->cur_blksize)
213 size -= smsdev->func->cur_blksize;
214 else
215 size = 0;
216 }
217 }
218 }
219
220 cb->size = hdr->msgLength;
221 cb->offset = 0;
222
223 smscore_onresponse(smsdev->coredev, cb);
224}
225
226static int __devinit smssdio_probe(struct sdio_func *func,
227 const struct sdio_device_id *id)
228{
229 int ret;
230
231 int board_id;
232 struct smssdio_device *smsdev;
233 struct smsdevice_params_t params;
234
235 board_id = id->driver_data;
236
237 smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
238 if (!smsdev)
239 return -ENOMEM;
240
241 smsdev->func = func;
242
243 memset(&params, 0, sizeof(struct smsdevice_params_t));
244
245 params.device = &func->dev;
246 params.buffer_size = 0x5000; /* ?? */
247 params.num_buffers = 22; /* ?? */
248 params.context = smsdev;
249
250 snprintf(params.devpath, sizeof(params.devpath),
251 "sdio\\%s", sdio_func_id(func));
252
253 params.sendrequest_handler = smssdio_sendrequest;
254
255 params.device_type = sms_get_board(board_id)->type;
256
257 if (params.device_type != SMS_STELLAR)
258 params.flags |= SMS_DEVICE_FAMILY2;
259 else {
260 /*
261 * FIXME: Stellar needs special handling...
262 */
263 ret = -ENODEV;
264 goto free;
265 }
266
267 ret = smscore_register_device(&params, &smsdev->coredev);
268 if (ret < 0)
269 goto free;
270
271 smscore_set_board_id(smsdev->coredev, board_id);
272
273 sdio_claim_host(func);
274
275 ret = sdio_enable_func(func);
276 if (ret)
277 goto release;
278
279 ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
280 if (ret)
281 goto disable;
282
283 ret = sdio_claim_irq(func, smssdio_interrupt);
284 if (ret)
285 goto disable;
286
287 sdio_set_drvdata(func, smsdev);
288
289 sdio_release_host(func);
290
291 ret = smscore_start_device(smsdev->coredev);
292 if (ret < 0)
293 goto reclaim;
294
295 return 0;
296
297reclaim:
298 sdio_claim_host(func);
299 sdio_release_irq(func);
300disable:
301 sdio_disable_func(func);
302release:
303 sdio_release_host(func);
304 smscore_unregister_device(smsdev->coredev);
305free:
306 kfree(smsdev);
307
308 return ret;
309}
310
311static void smssdio_remove(struct sdio_func *func)
312{
313 struct smssdio_device *smsdev;
314
315 smsdev = sdio_get_drvdata(func);
316
317 /* FIXME: racy! */
318 if (smsdev->split_cb)
319 smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
320
321 smscore_unregister_device(smsdev->coredev);
322
323 sdio_claim_host(func);
324 sdio_release_irq(func);
325 sdio_disable_func(func);
326 sdio_release_host(func);
327
328 kfree(smsdev);
329}
330
331static struct sdio_driver smssdio_driver = {
332 .name = "smssdio",
333 .id_table = smssdio_ids,
334 .probe = smssdio_probe,
335 .remove = smssdio_remove,
336};
337
338/*******************************************************************/
339/* Module functions */
340/*******************************************************************/
341
342static int __init smssdio_module_init(void)
343{
344 int ret = 0;
345
346 printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
347 printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
348
349 ret = sdio_register_driver(&smssdio_driver);
350
351 return ret;
352}
353
354static void __exit smssdio_module_exit(void)
355{
356 sdio_unregister_driver(&smssdio_driver);
357}
358
359module_init(smssdio_module_init);
360module_exit(smssdio_module_exit);
361
362MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
363MODULE_AUTHOR("Pierre Ossman");
364MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
new file mode 100644
index 00000000000..0c8164a2cc3
--- /dev/null
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -0,0 +1,582 @@
1/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2005-2009, 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#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/usb.h>
25#include <linux/firmware.h>
26#include <linux/slab.h>
27
28#include "smscoreapi.h"
29#include "sms-cards.h"
30#include "smsendian.h"
31
32static int sms_dbg;
33module_param_named(debug, sms_dbg, int, 0644);
34MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
35
36#define USB1_BUFFER_SIZE 0x1000
37#define USB2_BUFFER_SIZE 0x4000
38
39#define MAX_BUFFERS 50
40#define MAX_URBS 10
41
42struct smsusb_device_t;
43
44struct smsusb_urb_t {
45 struct smscore_buffer_t *cb;
46 struct smsusb_device_t *dev;
47
48 struct urb urb;
49};
50
51struct smsusb_device_t {
52 struct usb_device *udev;
53 struct smscore_device_t *coredev;
54
55 struct smsusb_urb_t surbs[MAX_URBS];
56
57 int response_alignment;
58 int buffer_size;
59};
60
61static int smsusb_submit_urb(struct smsusb_device_t *dev,
62 struct smsusb_urb_t *surb);
63
64static void smsusb_onresponse(struct urb *urb)
65{
66 struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
67 struct smsusb_device_t *dev = surb->dev;
68
69 if (urb->status == -ESHUTDOWN) {
70 sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
71 urb->status, urb->actual_length);
72 return;
73 }
74
75 if ((urb->actual_length > 0) && (urb->status == 0)) {
76 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
77
78 smsendian_handle_message_header(phdr);
79 if (urb->actual_length >= phdr->msgLength) {
80 surb->cb->size = phdr->msgLength;
81
82 if (dev->response_alignment &&
83 (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
84
85 surb->cb->offset =
86 dev->response_alignment +
87 ((phdr->msgFlags >> 8) & 3);
88
89 /* sanity check */
90 if (((int) phdr->msgLength +
91 surb->cb->offset) > urb->actual_length) {
92 sms_err("invalid response "
93 "msglen %d offset %d "
94 "size %d",
95 phdr->msgLength,
96 surb->cb->offset,
97 urb->actual_length);
98 goto exit_and_resubmit;
99 }
100
101 /* move buffer pointer and
102 * copy header to its new location */
103 memcpy((char *) phdr + surb->cb->offset,
104 phdr, sizeof(struct SmsMsgHdr_ST));
105 } else
106 surb->cb->offset = 0;
107
108 smscore_onresponse(dev->coredev, surb->cb);
109 surb->cb = NULL;
110 } else {
111 sms_err("invalid response "
112 "msglen %d actual %d",
113 phdr->msgLength, urb->actual_length);
114 }
115 } else
116 sms_err("error, urb status %d, %d bytes",
117 urb->status, urb->actual_length);
118
119
120exit_and_resubmit:
121 smsusb_submit_urb(dev, surb);
122}
123
124static int smsusb_submit_urb(struct smsusb_device_t *dev,
125 struct smsusb_urb_t *surb)
126{
127 if (!surb->cb) {
128 surb->cb = smscore_getbuffer(dev->coredev);
129 if (!surb->cb) {
130 sms_err("smscore_getbuffer(...) returned NULL");
131 return -ENOMEM;
132 }
133 }
134
135 usb_fill_bulk_urb(
136 &surb->urb,
137 dev->udev,
138 usb_rcvbulkpipe(dev->udev, 0x81),
139 surb->cb->p,
140 dev->buffer_size,
141 smsusb_onresponse,
142 surb
143 );
144 surb->urb.transfer_dma = surb->cb->phys;
145 surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
146
147 return usb_submit_urb(&surb->urb, GFP_ATOMIC);
148}
149
150static void smsusb_stop_streaming(struct smsusb_device_t *dev)
151{
152 int i;
153
154 for (i = 0; i < MAX_URBS; i++) {
155 usb_kill_urb(&dev->surbs[i].urb);
156
157 if (dev->surbs[i].cb) {
158 smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
159 dev->surbs[i].cb = NULL;
160 }
161 }
162}
163
164static int smsusb_start_streaming(struct smsusb_device_t *dev)
165{
166 int i, rc;
167
168 for (i = 0; i < MAX_URBS; i++) {
169 rc = smsusb_submit_urb(dev, &dev->surbs[i]);
170 if (rc < 0) {
171 sms_err("smsusb_submit_urb(...) failed");
172 smsusb_stop_streaming(dev);
173 break;
174 }
175 }
176
177 return rc;
178}
179
180static int smsusb_sendrequest(void *context, void *buffer, size_t size)
181{
182 struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
183 int dummy;
184
185 smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
186 return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
187 buffer, size, &dummy, 1000);
188}
189
190static char *smsusb1_fw_lkup[] = {
191 "dvbt_stellar_usb.inp",
192 "dvbh_stellar_usb.inp",
193 "tdmb_stellar_usb.inp",
194 "none",
195 "dvbt_bda_stellar_usb.inp",
196};
197
198static inline char *sms_get_fw_name(int mode, int board_id)
199{
200 char **fw = sms_get_board(board_id)->fw;
201 return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
202}
203
204static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
205{
206 const struct firmware *fw;
207 u8 *fw_buffer;
208 int rc, dummy;
209 char *fw_filename;
210
211 if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
212 sms_err("invalid firmware id specified %d", id);
213 return -EINVAL;
214 }
215
216 fw_filename = sms_get_fw_name(id, board_id);
217
218 rc = request_firmware(&fw, fw_filename, &udev->dev);
219 if (rc < 0) {
220 sms_warn("failed to open \"%s\" mode %d, "
221 "trying again with default firmware", fw_filename, id);
222
223 fw_filename = smsusb1_fw_lkup[id];
224 rc = request_firmware(&fw, fw_filename, &udev->dev);
225 if (rc < 0) {
226 sms_warn("failed to open \"%s\" mode %d",
227 fw_filename, id);
228
229 return rc;
230 }
231 }
232
233 fw_buffer = kmalloc(fw->size, GFP_KERNEL);
234 if (fw_buffer) {
235 memcpy(fw_buffer, fw->data, fw->size);
236
237 rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
238 fw_buffer, fw->size, &dummy, 1000);
239
240 sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
241
242 kfree(fw_buffer);
243 } else {
244 sms_err("failed to allocate firmware buffer");
245 rc = -ENOMEM;
246 }
247 sms_info("read FW %s, size=%zd", fw_filename, fw->size);
248
249 release_firmware(fw);
250
251 return rc;
252}
253
254static void smsusb1_detectmode(void *context, int *mode)
255{
256 char *product_string =
257 ((struct smsusb_device_t *) context)->udev->product;
258
259 *mode = DEVICE_MODE_NONE;
260
261 if (!product_string) {
262 product_string = "none";
263 sms_err("product string not found");
264 } else if (strstr(product_string, "DVBH"))
265 *mode = 1;
266 else if (strstr(product_string, "BDA"))
267 *mode = 4;
268 else if (strstr(product_string, "DVBT"))
269 *mode = 0;
270 else if (strstr(product_string, "TDMB"))
271 *mode = 2;
272
273 sms_info("%d \"%s\"", *mode, product_string);
274}
275
276static int smsusb1_setmode(void *context, int mode)
277{
278 struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
279 sizeof(struct SmsMsgHdr_ST), 0 };
280
281 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
282 sms_err("invalid firmware id specified %d", mode);
283 return -EINVAL;
284 }
285
286 return smsusb_sendrequest(context, &Msg, sizeof(Msg));
287}
288
289static void smsusb_term_device(struct usb_interface *intf)
290{
291 struct smsusb_device_t *dev = usb_get_intfdata(intf);
292
293 if (dev) {
294 smsusb_stop_streaming(dev);
295
296 /* unregister from smscore */
297 if (dev->coredev)
298 smscore_unregister_device(dev->coredev);
299
300 sms_info("device %p destroyed", dev);
301 kfree(dev);
302 }
303
304 usb_set_intfdata(intf, NULL);
305}
306
307static int smsusb_init_device(struct usb_interface *intf, int board_id)
308{
309 struct smsdevice_params_t params;
310 struct smsusb_device_t *dev;
311 int i, rc;
312
313 /* create device object */
314 dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
315 if (!dev) {
316 sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
317 return -ENOMEM;
318 }
319
320 memset(&params, 0, sizeof(params));
321 usb_set_intfdata(intf, dev);
322 dev->udev = interface_to_usbdev(intf);
323
324 params.device_type = sms_get_board(board_id)->type;
325
326 switch (params.device_type) {
327 case SMS_STELLAR:
328 dev->buffer_size = USB1_BUFFER_SIZE;
329
330 params.setmode_handler = smsusb1_setmode;
331 params.detectmode_handler = smsusb1_detectmode;
332 break;
333 default:
334 sms_err("Unspecified sms device type!");
335 /* fall-thru */
336 case SMS_NOVA_A0:
337 case SMS_NOVA_B0:
338 case SMS_VEGA:
339 dev->buffer_size = USB2_BUFFER_SIZE;
340 dev->response_alignment =
341 le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
342 sizeof(struct SmsMsgHdr_ST);
343
344 params.flags |= SMS_DEVICE_FAMILY2;
345 break;
346 }
347
348 params.device = &dev->udev->dev;
349 params.buffer_size = dev->buffer_size;
350 params.num_buffers = MAX_BUFFERS;
351 params.sendrequest_handler = smsusb_sendrequest;
352 params.context = dev;
353 usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
354
355 /* register in smscore */
356 rc = smscore_register_device(&params, &dev->coredev);
357 if (rc < 0) {
358 sms_err("smscore_register_device(...) failed, rc %d", rc);
359 smsusb_term_device(intf);
360 return rc;
361 }
362
363 smscore_set_board_id(dev->coredev, board_id);
364
365 /* initialize urbs */
366 for (i = 0; i < MAX_URBS; i++) {
367 dev->surbs[i].dev = dev;
368 usb_init_urb(&dev->surbs[i].urb);
369 }
370
371 sms_info("smsusb_start_streaming(...).");
372 rc = smsusb_start_streaming(dev);
373 if (rc < 0) {
374 sms_err("smsusb_start_streaming(...) failed");
375 smsusb_term_device(intf);
376 return rc;
377 }
378
379 rc = smscore_start_device(dev->coredev);
380 if (rc < 0) {
381 sms_err("smscore_start_device(...) failed");
382 smsusb_term_device(intf);
383 return rc;
384 }
385
386 sms_info("device %p created", dev);
387
388 return rc;
389}
390
391static int __devinit smsusb_probe(struct usb_interface *intf,
392 const struct usb_device_id *id)
393{
394 struct usb_device *udev = interface_to_usbdev(intf);
395 char devpath[32];
396 int i, rc;
397
398 rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
399 rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
400
401 if (intf->num_altsetting > 0) {
402 rc = usb_set_interface(
403 udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
404 if (rc < 0) {
405 sms_err("usb_set_interface failed, rc %d", rc);
406 return rc;
407 }
408 }
409
410 sms_info("smsusb_probe %d",
411 intf->cur_altsetting->desc.bInterfaceNumber);
412 for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
413 sms_info("endpoint %d %02x %02x %d", i,
414 intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
415 intf->cur_altsetting->endpoint[i].desc.bmAttributes,
416 intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
417
418 if ((udev->actconfig->desc.bNumInterfaces == 2) &&
419 (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
420 sms_err("rom interface 0 is not used");
421 return -ENODEV;
422 }
423
424 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
425 snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
426 udev->bus->busnum, udev->devpath);
427 sms_info("stellar device was found.");
428 return smsusb1_load_firmware(
429 udev, smscore_registry_getmode(devpath),
430 id->driver_info);
431 }
432
433 rc = smsusb_init_device(intf, id->driver_info);
434 sms_info("rc %d", rc);
435 sms_board_load_modules(id->driver_info);
436 return rc;
437}
438
439static void smsusb_disconnect(struct usb_interface *intf)
440{
441 smsusb_term_device(intf);
442}
443
444static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
445{
446 struct smsusb_device_t *dev = usb_get_intfdata(intf);
447 printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
448 smsusb_stop_streaming(dev);
449 return 0;
450}
451
452static int smsusb_resume(struct usb_interface *intf)
453{
454 int rc, i;
455 struct smsusb_device_t *dev = usb_get_intfdata(intf);
456 struct usb_device *udev = interface_to_usbdev(intf);
457
458 printk(KERN_INFO "%s: Entering.\n", __func__);
459 usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
460 usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
461
462 for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
463 printk(KERN_INFO "endpoint %d %02x %02x %d\n", i,
464 intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
465 intf->cur_altsetting->endpoint[i].desc.bmAttributes,
466 intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
467
468 if (intf->num_altsetting > 0) {
469 rc = usb_set_interface(udev,
470 intf->cur_altsetting->desc.
471 bInterfaceNumber, 0);
472 if (rc < 0) {
473 printk(KERN_INFO "%s usb_set_interface failed, "
474 "rc %d\n", __func__, rc);
475 return rc;
476 }
477 }
478
479 smsusb_start_streaming(dev);
480 return 0;
481}
482
483static const struct usb_device_id smsusb_id_table[] __devinitconst = {
484 { USB_DEVICE(0x187f, 0x0010),
485 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
486 { USB_DEVICE(0x187f, 0x0100),
487 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
488 { USB_DEVICE(0x187f, 0x0200),
489 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
490 { USB_DEVICE(0x187f, 0x0201),
491 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
492 { USB_DEVICE(0x187f, 0x0300),
493 .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
494 { USB_DEVICE(0x2040, 0x1700),
495 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
496 { USB_DEVICE(0x2040, 0x1800),
497 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
498 { USB_DEVICE(0x2040, 0x1801),
499 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
500 { USB_DEVICE(0x2040, 0x2000),
501 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
502 { USB_DEVICE(0x2040, 0x2009),
503 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 },
504 { USB_DEVICE(0x2040, 0x200a),
505 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
506 { USB_DEVICE(0x2040, 0x2010),
507 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
508 { USB_DEVICE(0x2040, 0x2011),
509 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
510 { USB_DEVICE(0x2040, 0x2019),
511 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD },
512 { USB_DEVICE(0x2040, 0x5500),
513 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
514 { USB_DEVICE(0x2040, 0x5510),
515 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
516 { USB_DEVICE(0x2040, 0x5520),
517 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
518 { USB_DEVICE(0x2040, 0x5530),
519 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
520 { USB_DEVICE(0x2040, 0x5580),
521 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
522 { USB_DEVICE(0x2040, 0x5590),
523 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
524 { USB_DEVICE(0x187f, 0x0202),
525 .driver_info = SMS1XXX_BOARD_SIANO_NICE },
526 { USB_DEVICE(0x187f, 0x0301),
527 .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
528 { USB_DEVICE(0x2040, 0xb900),
529 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
530 { USB_DEVICE(0x2040, 0xb910),
531 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
532 { USB_DEVICE(0x2040, 0xb980),
533 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
534 { USB_DEVICE(0x2040, 0xb990),
535 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
536 { USB_DEVICE(0x2040, 0xc000),
537 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
538 { USB_DEVICE(0x2040, 0xc010),
539 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
540 { USB_DEVICE(0x2040, 0xc080),
541 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
542 { USB_DEVICE(0x2040, 0xc090),
543 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
544 { } /* Terminating entry */
545 };
546
547MODULE_DEVICE_TABLE(usb, smsusb_id_table);
548
549static struct usb_driver smsusb_driver = {
550 .name = "smsusb",
551 .probe = smsusb_probe,
552 .disconnect = smsusb_disconnect,
553 .id_table = smsusb_id_table,
554
555 .suspend = smsusb_suspend,
556 .resume = smsusb_resume,
557};
558
559static int __init smsusb_module_init(void)
560{
561 int rc = usb_register(&smsusb_driver);
562 if (rc)
563 sms_err("usb_register failed. Error number %d", rc);
564
565 sms_debug("");
566
567 return rc;
568}
569
570static void __exit smsusb_module_exit(void)
571{
572 /* Regular USB Cleanup */
573 usb_deregister(&smsusb_driver);
574 sms_info("end");
575}
576
577module_init(smsusb_module_init);
578module_exit(smsusb_module_exit);
579
580MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
581MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
582MODULE_LICENSE("GPL");