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/Kconfig26
-rw-r--r--drivers/media/dvb/siano/Makefile8
-rw-r--r--drivers/media/dvb/siano/sms-cards.c102
-rw-r--r--drivers/media/dvb/siano/sms-cards.h45
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c1251
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h434
-rw-r--r--drivers/media/dvb/siano/smsdvb.c449
-rw-r--r--drivers/media/dvb/siano/smsusb.c459
8 files changed, 2774 insertions, 0 deletions
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
new file mode 100644
index 000000000000..dd863f261672
--- /dev/null
+++ b/drivers/media/dvb/siano/Kconfig
@@ -0,0 +1,26 @@
1#
2# Siano Mobile Silicon Digital TV device configuration
3#
4
5config DVB_SIANO_SMS1XXX
6 tristate "Siano SMS1XXX USB dongle support"
7 depends on DVB_CORE && USB
8 ---help---
9 Choose Y here if you have a USB dongle with a SMS1XXX chipset.
10
11 To compile this driver as a module, choose M here: the
12 module will be called sms1xxx.
13
14config DVB_SIANO_SMS1XXX_SMS_IDS
15 bool "Enable support for Siano Mobile Silicon default USB IDs"
16 depends on DVB_SIANO_SMS1XXX
17 default y
18 ---help---
19 Choose Y here if you have a USB dongle with a SMS1XXX chipset
20 that uses Siano Mobile Silicon's default usb vid:pid.
21
22 Choose N here if you would prefer to use Siano's external driver.
23
24 Further documentation on this driver can be found on the WWW at
25 <http://www.siano-ms.com/>.
26
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
new file mode 100644
index 000000000000..ee0737af98c0
--- /dev/null
+++ b/drivers/media/dvb/siano/Makefile
@@ -0,0 +1,8 @@
1sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.o sms-cards.o
2
3obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
4
5EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
6
7EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
8
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
new file mode 100644
index 000000000000..e7a8ac0c4049
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -0,0 +1,102 @@
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 3 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
22struct usb_device_id smsusb_id_table[] = {
23#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
24 { USB_DEVICE(0x187f, 0x0010),
25 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
26 { USB_DEVICE(0x187f, 0x0100),
27 .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
28 { USB_DEVICE(0x187f, 0x0200),
29 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_A },
30 { USB_DEVICE(0x187f, 0x0201),
31 .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
32 { USB_DEVICE(0x187f, 0x0300),
33 .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
34#endif
35 { USB_DEVICE(0x2040, 0x1700),
36 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
37 { USB_DEVICE(0x2040, 0x1800),
38 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A },
39 { USB_DEVICE(0x2040, 0x1801),
40 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B },
41 { USB_DEVICE(0x2040, 0x5500),
42 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
43 { USB_DEVICE(0x2040, 0x5580),
44 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
45 { USB_DEVICE(0x2040, 0x5590),
46 .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
47 { } /* Terminating entry */
48};
49MODULE_DEVICE_TABLE(usb, smsusb_id_table);
50
51static struct sms_board sms_boards[] = {
52 [SMS_BOARD_UNKNOWN] = {
53 .name = "Unknown board",
54 },
55 [SMS1XXX_BOARD_SIANO_STELLAR] = {
56 .name = "Siano Stellar Digital Receiver",
57 .type = SMS_STELLAR,
58 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
59 },
60 [SMS1XXX_BOARD_SIANO_NOVA_A] = {
61 .name = "Siano Nova A Digital Receiver",
62 .type = SMS_NOVA_A0,
63 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
64 },
65 [SMS1XXX_BOARD_SIANO_NOVA_B] = {
66 .name = "Siano Nova B Digital Receiver",
67 .type = SMS_NOVA_B0,
68 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
69 },
70 [SMS1XXX_BOARD_SIANO_VEGA] = {
71 .name = "Siano Vega Digital Receiver",
72 .type = SMS_VEGA,
73 },
74 [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = {
75 .name = "Hauppauge Catamount",
76 .type = SMS_STELLAR,
77 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
78 },
79 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = {
80 .name = "Hauppauge Okemo-A",
81 .type = SMS_NOVA_A0,
82 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
83 },
84 [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = {
85 .name = "Hauppauge Okemo-B",
86 .type = SMS_NOVA_B0,
87 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
88 },
89 [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = {
90 .name = "Hauppauge WinTV-Nova-T-MiniStick",
91 .type = SMS_NOVA_B0,
92 .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-01.fw",
93 },
94};
95
96struct sms_board *sms_get_board(int id)
97{
98 BUG_ON(id >= ARRAY_SIZE(sms_boards));
99
100 return &sms_boards[id];
101}
102
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
new file mode 100644
index 000000000000..83b39bc203fe
--- /dev/null
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -0,0 +1,45 @@
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 3 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
26#define SMS_BOARD_UNKNOWN 0
27#define SMS1XXX_BOARD_SIANO_STELLAR 1
28#define SMS1XXX_BOARD_SIANO_NOVA_A 2
29#define SMS1XXX_BOARD_SIANO_NOVA_B 3
30#define SMS1XXX_BOARD_SIANO_VEGA 4
31#define SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT 5
32#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A 6
33#define SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B 7
34#define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
35
36struct sms_board {
37 enum sms_device_type_st type;
38 char *name, *fw[DEVICE_MODE_MAX];
39};
40
41struct sms_board *sms_get_board(int id);
42
43extern struct usb_device_id smsusb_id_table[];
44
45#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 000000000000..b4b8ed795c95
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -0,0 +1,1251 @@
1/*
2 * Siano core API module
3 *
4 * This file contains implementation for the interface to sms core component
5 *
6 * author: Anatoly Greenblat
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 3 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
32#include <linux/firmware.h>
33
34#include "smscoreapi.h"
35#include "sms-cards.h"
36
37int sms_debug;
38module_param_named(debug, sms_debug, int, 0644);
39MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
40
41struct smscore_device_notifyee_t {
42 struct list_head entry;
43 hotplug_t hotplug;
44};
45
46struct smscore_idlist_t {
47 struct list_head entry;
48 int id;
49 int data_type;
50};
51
52struct smscore_client_t {
53 struct list_head entry;
54 struct smscore_device_t *coredev;
55 void *context;
56 struct list_head idlist;
57 onresponse_t onresponse_handler;
58 onremove_t onremove_handler;
59};
60
61struct smscore_device_t {
62 struct list_head entry;
63
64 struct list_head clients;
65 struct list_head subclients;
66 spinlock_t clientslock;
67
68 struct list_head buffers;
69 spinlock_t bufferslock;
70 int num_buffers;
71
72 void *common_buffer;
73 int common_buffer_size;
74 dma_addr_t common_buffer_phys;
75
76 void *context;
77 struct device *device;
78
79 char devpath[32];
80 unsigned long device_flags;
81
82 setmode_t setmode_handler;
83 detectmode_t detectmode_handler;
84 sendrequest_t sendrequest_handler;
85 preload_t preload_handler;
86 postload_t postload_handler;
87
88 int mode, modes_supported;
89
90 struct completion version_ex_done, data_download_done, trigger_done;
91 struct completion init_device_done, reload_start_done, resume_done;
92
93 int board_id;
94};
95
96void smscore_set_board_id(struct smscore_device_t *core, int id)
97{
98 core->board_id = id;
99}
100
101int smscore_get_board_id(struct smscore_device_t *core)
102{
103 return core->board_id;
104}
105
106struct smscore_registry_entry_t {
107 struct list_head entry;
108 char devpath[32];
109 int mode;
110 enum sms_device_type_st type;
111};
112
113struct list_head g_smscore_notifyees;
114struct list_head g_smscore_devices;
115struct mutex g_smscore_deviceslock;
116
117struct list_head g_smscore_registry;
118struct mutex g_smscore_registrylock;
119
120static int default_mode = 4;
121
122module_param(default_mode, int, 0644);
123MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
124
125static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
126{
127 struct smscore_registry_entry_t *entry;
128 struct list_head *next;
129
130 kmutex_lock(&g_smscore_registrylock);
131 for (next = g_smscore_registry.next;
132 next != &g_smscore_registry;
133 next = next->next) {
134 entry = (struct smscore_registry_entry_t *) next;
135 if (!strcmp(entry->devpath, devpath)) {
136 kmutex_unlock(&g_smscore_registrylock);
137 return entry;
138 }
139 }
140 entry = (struct smscore_registry_entry_t *)
141 kmalloc(sizeof(struct smscore_registry_entry_t),
142 GFP_KERNEL);
143 if (entry) {
144 entry->mode = default_mode;
145 strcpy(entry->devpath, devpath);
146 list_add(&entry->entry, &g_smscore_registry);
147 } else
148 sms_err("failed to create smscore_registry.");
149 kmutex_unlock(&g_smscore_registrylock);
150 return entry;
151}
152
153int smscore_registry_getmode(char *devpath)
154{
155 struct smscore_registry_entry_t *entry;
156
157 entry = smscore_find_registry(devpath);
158 if (entry)
159 return entry->mode;
160 else
161 sms_err("No registry found.");
162
163 return default_mode;
164}
165
166static enum sms_device_type_st smscore_registry_gettype(char *devpath)
167{
168 struct smscore_registry_entry_t *entry;
169
170 entry = smscore_find_registry(devpath);
171 if (entry)
172 return entry->type;
173 else
174 sms_err("No registry found.");
175
176 return -1;
177}
178
179void smscore_registry_setmode(char *devpath, int mode)
180{
181 struct smscore_registry_entry_t *entry;
182
183 entry = smscore_find_registry(devpath);
184 if (entry)
185 entry->mode = mode;
186 else
187 sms_err("No registry found.");
188}
189
190static void smscore_registry_settype(char *devpath,
191 enum sms_device_type_st type)
192{
193 struct smscore_registry_entry_t *entry;
194
195 entry = smscore_find_registry(devpath);
196 if (entry)
197 entry->type = type;
198 else
199 sms_err("No registry found.");
200}
201
202
203static void list_add_locked(struct list_head *new, struct list_head *head,
204 spinlock_t *lock)
205{
206 unsigned long flags;
207
208 spin_lock_irqsave(lock, flags);
209
210 list_add(new, head);
211
212 spin_unlock_irqrestore(lock, flags);
213}
214
215/**
216 * register a client callback that called when device plugged in/unplugged
217 * NOTE: if devices exist callback is called immediately for each device
218 *
219 * @param hotplug callback
220 *
221 * @return 0 on success, <0 on error.
222 */
223int smscore_register_hotplug(hotplug_t hotplug)
224{
225 struct smscore_device_notifyee_t *notifyee;
226 struct list_head *next, *first;
227 int rc = 0;
228
229 kmutex_lock(&g_smscore_deviceslock);
230
231 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
232 GFP_KERNEL);
233 if (notifyee) {
234 /* now notify callback about existing devices */
235 first = &g_smscore_devices;
236 for (next = first->next;
237 next != first && !rc;
238 next = next->next) {
239 struct smscore_device_t *coredev =
240 (struct smscore_device_t *) next;
241 rc = hotplug(coredev, coredev->device, 1);
242 }
243
244 if (rc >= 0) {
245 notifyee->hotplug = hotplug;
246 list_add(&notifyee->entry, &g_smscore_notifyees);
247 } else
248 kfree(notifyee);
249 } else
250 rc = -ENOMEM;
251
252 kmutex_unlock(&g_smscore_deviceslock);
253
254 return rc;
255}
256
257/**
258 * unregister a client callback that called when device plugged in/unplugged
259 *
260 * @param hotplug callback
261 *
262 */
263void smscore_unregister_hotplug(hotplug_t hotplug)
264{
265 struct list_head *next, *first;
266
267 kmutex_lock(&g_smscore_deviceslock);
268
269 first = &g_smscore_notifyees;
270
271 for (next = first->next; next != first;) {
272 struct smscore_device_notifyee_t *notifyee =
273 (struct smscore_device_notifyee_t *) next;
274 next = next->next;
275
276 if (notifyee->hotplug == hotplug) {
277 list_del(&notifyee->entry);
278 kfree(notifyee);
279 }
280 }
281
282 kmutex_unlock(&g_smscore_deviceslock);
283}
284
285static void smscore_notify_clients(struct smscore_device_t *coredev)
286{
287 struct smscore_client_t *client;
288
289 /* the client must call smscore_unregister_client from remove handler */
290 while (!list_empty(&coredev->clients)) {
291 client = (struct smscore_client_t *) coredev->clients.next;
292 client->onremove_handler(client->context);
293 }
294}
295
296static int smscore_notify_callbacks(struct smscore_device_t *coredev,
297 struct device *device, int arrival)
298{
299 struct list_head *next, *first;
300 int rc = 0;
301
302 /* note: must be called under g_deviceslock */
303
304 first = &g_smscore_notifyees;
305
306 for (next = first->next; next != first; next = next->next) {
307 rc = ((struct smscore_device_notifyee_t *) next)->
308 hotplug(coredev, device, arrival);
309 if (rc < 0)
310 break;
311 }
312
313 return rc;
314}
315
316static struct
317smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
318 dma_addr_t common_buffer_phys)
319{
320 struct smscore_buffer_t *cb =
321 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
322 if (!cb) {
323 sms_info("kmalloc(...) failed");
324 return NULL;
325 }
326
327 cb->p = buffer;
328 cb->offset_in_common = buffer - (u8 *) common_buffer;
329 cb->phys = common_buffer_phys + cb->offset_in_common;
330
331 return cb;
332}
333
334/**
335 * creates coredev object for a device, prepares buffers,
336 * creates buffer mappings, notifies registered hotplugs about new device.
337 *
338 * @param params device pointer to struct with device specific parameters
339 * and handlers
340 * @param coredev pointer to a value that receives created coredev object
341 *
342 * @return 0 on success, <0 on error.
343 */
344int smscore_register_device(struct smsdevice_params_t *params,
345 struct smscore_device_t **coredev)
346{
347 struct smscore_device_t *dev;
348 u8 *buffer;
349
350 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
351 if (!dev) {
352 sms_info("kzalloc(...) failed");
353 return -ENOMEM;
354 }
355
356 /* init list entry so it could be safe in smscore_unregister_device */
357 INIT_LIST_HEAD(&dev->entry);
358
359 /* init queues */
360 INIT_LIST_HEAD(&dev->clients);
361 INIT_LIST_HEAD(&dev->buffers);
362
363 /* init locks */
364 spin_lock_init(&dev->clientslock);
365 spin_lock_init(&dev->bufferslock);
366
367 /* init completion events */
368 init_completion(&dev->version_ex_done);
369 init_completion(&dev->data_download_done);
370 init_completion(&dev->trigger_done);
371 init_completion(&dev->init_device_done);
372 init_completion(&dev->reload_start_done);
373 init_completion(&dev->resume_done);
374
375 /* alloc common buffer */
376 dev->common_buffer_size = params->buffer_size * params->num_buffers;
377 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
378 &dev->common_buffer_phys,
379 GFP_KERNEL | GFP_DMA);
380 if (!dev->common_buffer) {
381 smscore_unregister_device(dev);
382 return -ENOMEM;
383 }
384
385 /* prepare dma buffers */
386 for (buffer = dev->common_buffer;
387 dev->num_buffers < params->num_buffers;
388 dev->num_buffers++, buffer += params->buffer_size) {
389 struct smscore_buffer_t *cb =
390 smscore_createbuffer(buffer, dev->common_buffer,
391 dev->common_buffer_phys);
392 if (!cb) {
393 smscore_unregister_device(dev);
394 return -ENOMEM;
395 }
396
397 smscore_putbuffer(dev, cb);
398 }
399
400 sms_info("allocated %d buffers", dev->num_buffers);
401
402 dev->mode = DEVICE_MODE_NONE;
403 dev->context = params->context;
404 dev->device = params->device;
405 dev->setmode_handler = params->setmode_handler;
406 dev->detectmode_handler = params->detectmode_handler;
407 dev->sendrequest_handler = params->sendrequest_handler;
408 dev->preload_handler = params->preload_handler;
409 dev->postload_handler = params->postload_handler;
410
411 dev->device_flags = params->flags;
412 strcpy(dev->devpath, params->devpath);
413
414 smscore_registry_settype(dev->devpath, params->device_type);
415
416 /* add device to devices list */
417 kmutex_lock(&g_smscore_deviceslock);
418 list_add(&dev->entry, &g_smscore_devices);
419 kmutex_unlock(&g_smscore_deviceslock);
420
421 *coredev = dev;
422
423 sms_info("device %p created", dev);
424
425 return 0;
426}
427
428/**
429 * sets initial device mode and notifies client hotplugs that device is ready
430 *
431 * @param coredev pointer to a coredev object returned by
432 * smscore_register_device
433 *
434 * @return 0 on success, <0 on error.
435 */
436int smscore_start_device(struct smscore_device_t *coredev)
437{
438 int rc = smscore_set_device_mode(
439 coredev, smscore_registry_getmode(coredev->devpath));
440 if (rc < 0) {
441 sms_info("set device mode faile , rc %d", rc);
442 return rc;
443 }
444
445 kmutex_lock(&g_smscore_deviceslock);
446
447 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
448
449 sms_info("device %p started, rc %d", coredev, rc);
450
451 kmutex_unlock(&g_smscore_deviceslock);
452
453 return rc;
454}
455
456static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
457 void *buffer, size_t size,
458 struct completion *completion)
459{
460 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
461 if (rc < 0) {
462 sms_info("sendrequest returned error %d", rc);
463 return rc;
464 }
465
466 return wait_for_completion_timeout(completion,
467 msecs_to_jiffies(10000)) ?
468 0 : -ETIME;
469}
470
471static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
472 void *buffer, size_t size)
473{
474 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
475 struct SmsMsgHdr_ST *msg;
476 u32 mem_address = firmware->StartAddress;
477 u8 *payload = firmware->Payload;
478 int rc = 0;
479
480 sms_info("loading FW to addr 0x%x size %d",
481 mem_address, firmware->Length);
482 if (coredev->preload_handler) {
483 rc = coredev->preload_handler(coredev->context);
484 if (rc < 0)
485 return rc;
486 }
487
488 /* PAGE_SIZE buffer shall be enough and dma aligned */
489 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
490 if (!msg)
491 return -ENOMEM;
492
493 if (coredev->mode != DEVICE_MODE_NONE) {
494 sms_debug("sending reload command.");
495 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
496 sizeof(struct SmsMsgHdr_ST));
497 rc = smscore_sendrequest_and_wait(coredev, msg,
498 msg->msgLength,
499 &coredev->reload_start_done);
500 mem_address = *(u32 *) &payload[20];
501 }
502
503 while (size && rc >= 0) {
504 struct SmsDataDownload_ST *DataMsg =
505 (struct SmsDataDownload_ST *) msg;
506 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
507
508 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
509 (u16)(sizeof(struct SmsMsgHdr_ST) +
510 sizeof(u32) + payload_size));
511
512 DataMsg->MemAddr = mem_address;
513 memcpy(DataMsg->Payload, payload, payload_size);
514
515 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
516 (coredev->mode == DEVICE_MODE_NONE))
517 rc = coredev->sendrequest_handler(
518 coredev->context, DataMsg,
519 DataMsg->xMsgHeader.msgLength);
520 else
521 rc = smscore_sendrequest_and_wait(
522 coredev, DataMsg,
523 DataMsg->xMsgHeader.msgLength,
524 &coredev->data_download_done);
525
526 payload += payload_size;
527 size -= payload_size;
528 mem_address += payload_size;
529 }
530
531 if (rc >= 0) {
532 if (coredev->mode == DEVICE_MODE_NONE) {
533 struct SmsMsgData_ST *TriggerMsg =
534 (struct SmsMsgData_ST *) msg;
535
536 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
537 sizeof(struct SmsMsgHdr_ST) +
538 sizeof(u32) * 5);
539
540 TriggerMsg->msgData[0] = firmware->StartAddress;
541 /* Entry point */
542 TriggerMsg->msgData[1] = 5; /* Priority */
543 TriggerMsg->msgData[2] = 0x200; /* Stack size */
544 TriggerMsg->msgData[3] = 0; /* Parameter */
545 TriggerMsg->msgData[4] = 4; /* Task ID */
546
547 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
548 rc = coredev->sendrequest_handler(
549 coredev->context, TriggerMsg,
550 TriggerMsg->xMsgHeader.msgLength);
551 msleep(100);
552 } else
553 rc = smscore_sendrequest_and_wait(
554 coredev, TriggerMsg,
555 TriggerMsg->xMsgHeader.msgLength,
556 &coredev->trigger_done);
557 } else {
558 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
559 sizeof(struct SmsMsgHdr_ST));
560
561 rc = coredev->sendrequest_handler(coredev->context,
562 msg, msg->msgLength);
563 }
564 msleep(500);
565 }
566
567 sms_debug("rc=%d, postload=%p ", rc,
568 coredev->postload_handler);
569
570 kfree(msg);
571
572 return ((rc >= 0) && coredev->postload_handler) ?
573 coredev->postload_handler(coredev->context) :
574 rc;
575}
576
577/**
578 * loads specified firmware into a buffer and calls device loadfirmware_handler
579 *
580 * @param coredev pointer to a coredev object returned by
581 * smscore_register_device
582 * @param filename null-terminated string specifies firmware file name
583 * @param loadfirmware_handler device handler that loads firmware
584 *
585 * @return 0 on success, <0 on error.
586 */
587static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
588 char *filename,
589 loadfirmware_t loadfirmware_handler)
590{
591 int rc = -ENOENT;
592 const struct firmware *fw;
593 u8 *fw_buffer;
594
595 if (loadfirmware_handler == NULL && !(coredev->device_flags &
596 SMS_DEVICE_FAMILY2))
597 return -EINVAL;
598
599 rc = request_firmware(&fw, filename, coredev->device);
600 if (rc < 0) {
601 sms_info("failed to open \"%s\"", filename);
602 return rc;
603 }
604 sms_info("read FW %s, size=%zd", filename, fw->size);
605 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
606 GFP_KERNEL | GFP_DMA);
607 if (fw_buffer) {
608 memcpy(fw_buffer, fw->data, fw->size);
609
610 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
611 smscore_load_firmware_family2(coredev,
612 fw_buffer,
613 fw->size) :
614 loadfirmware_handler(coredev->context,
615 fw_buffer, fw->size);
616
617 kfree(fw_buffer);
618 } else {
619 sms_info("failed to allocate firmware buffer");
620 rc = -ENOMEM;
621 }
622
623 release_firmware(fw);
624
625 return rc;
626}
627
628/**
629 * notifies all clients registered with the device, notifies hotplugs,
630 * frees all buffers and coredev object
631 *
632 * @param coredev pointer to a coredev object returned by
633 * smscore_register_device
634 *
635 * @return 0 on success, <0 on error.
636 */
637void smscore_unregister_device(struct smscore_device_t *coredev)
638{
639 struct smscore_buffer_t *cb;
640 int num_buffers = 0;
641 int retry = 0;
642
643 kmutex_lock(&g_smscore_deviceslock);
644
645 smscore_notify_clients(coredev);
646 smscore_notify_callbacks(coredev, NULL, 0);
647
648 /* at this point all buffers should be back
649 * onresponse must no longer be called */
650
651 while (1) {
652 while ((cb = smscore_getbuffer(coredev))) {
653 kfree(cb);
654 num_buffers++;
655 }
656 if (num_buffers == coredev->num_buffers)
657 break;
658 if (++retry > 10) {
659 sms_info("exiting although "
660 "not all buffers released.");
661 break;
662 }
663
664 sms_info("waiting for %d buffer(s)",
665 coredev->num_buffers - num_buffers);
666 msleep(100);
667 }
668
669 sms_info("freed %d buffers", num_buffers);
670
671 if (coredev->common_buffer)
672 dma_free_coherent(NULL, coredev->common_buffer_size,
673 coredev->common_buffer,
674 coredev->common_buffer_phys);
675
676 list_del(&coredev->entry);
677 kfree(coredev);
678
679 kmutex_unlock(&g_smscore_deviceslock);
680
681 sms_info("device %p destroyed", coredev);
682}
683
684static int smscore_detect_mode(struct smscore_device_t *coredev)
685{
686 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
687 GFP_KERNEL | GFP_DMA);
688 struct SmsMsgHdr_ST *msg =
689 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
690 int rc;
691
692 if (!buffer)
693 return -ENOMEM;
694
695 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
696 sizeof(struct SmsMsgHdr_ST));
697
698 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
699 &coredev->version_ex_done);
700 if (rc == -ETIME) {
701 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
702
703 if (wait_for_completion_timeout(&coredev->resume_done,
704 msecs_to_jiffies(5000))) {
705 rc = smscore_sendrequest_and_wait(
706 coredev, msg, msg->msgLength,
707 &coredev->version_ex_done);
708 if (rc < 0)
709 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
710 "second try, rc %d", rc);
711 } else
712 rc = -ETIME;
713 }
714
715 kfree(buffer);
716
717 return rc;
718}
719
720static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
721 /*Stellar NOVA A0 Nova B0 VEGA*/
722 /*DVBT*/
723 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
724 /*DVBH*/
725 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
726 /*TDMB*/
727 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
728 /*DABIP*/
729 {"none", "none", "none", "none"},
730 /*BDA*/
731 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
732 /*ISDBT*/
733 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
734 /*ISDBTBDA*/
735 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
736 /*CMMB*/
737 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
738};
739
740static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
741 int mode, enum sms_device_type_st type)
742{
743 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
744 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
745}
746
747/**
748 * calls device handler to change mode of operation
749 * NOTE: stellar/usb may disconnect when changing mode
750 *
751 * @param coredev pointer to a coredev object returned by
752 * smscore_register_device
753 * @param mode requested mode of operation
754 *
755 * @return 0 on success, <0 on error.
756 */
757int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
758{
759 void *buffer;
760 int rc = 0;
761 enum sms_device_type_st type;
762
763 sms_debug("set device mode to %d", mode);
764 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
765 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
766 sms_err("invalid mode specified %d", mode);
767 return -EINVAL;
768 }
769
770 smscore_registry_setmode(coredev->devpath, mode);
771
772 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
773 rc = smscore_detect_mode(coredev);
774 if (rc < 0) {
775 sms_err("mode detect failed %d", rc);
776 return rc;
777 }
778 }
779
780 if (coredev->mode == mode) {
781 sms_info("device mode %d already set", mode);
782 return 0;
783 }
784
785 if (!(coredev->modes_supported & (1 << mode))) {
786 char *fw_filename;
787
788 type = smscore_registry_gettype(coredev->devpath);
789 fw_filename = sms_get_fw_name(coredev, mode, type);
790
791 rc = smscore_load_firmware_from_file(coredev,
792 fw_filename, NULL);
793 if (rc < 0) {
794 sms_warn("error %d loading firmware: %s, "
795 "trying again with default firmware",
796 rc, fw_filename);
797
798 /* try again with the default firmware */
799 fw_filename = smscore_fw_lkup[mode][type];
800 rc = smscore_load_firmware_from_file(coredev,
801 fw_filename, NULL);
802
803 if (rc < 0) {
804 sms_warn("error %d loading "
805 "firmware: %s", rc,
806 fw_filename);
807 return rc;
808 }
809 }
810 sms_log("firmware download success: %s", fw_filename);
811 } else
812 sms_info("mode %d supported by running "
813 "firmware", mode);
814
815 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
816 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
817 if (buffer) {
818 struct SmsMsgData_ST *msg =
819 (struct SmsMsgData_ST *)
820 SMS_ALIGN_ADDRESS(buffer);
821
822 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
823 sizeof(struct SmsMsgData_ST));
824 msg->msgData[0] = mode;
825
826 rc = smscore_sendrequest_and_wait(
827 coredev, msg, msg->xMsgHeader.msgLength,
828 &coredev->init_device_done);
829
830 kfree(buffer);
831 } else {
832 sms_err("Could not allocate buffer for "
833 "init device message.");
834 rc = -ENOMEM;
835 }
836 } else {
837 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
838 sms_err("invalid mode specified %d", mode);
839 return -EINVAL;
840 }
841
842 smscore_registry_setmode(coredev->devpath, mode);
843
844 if (coredev->detectmode_handler)
845 coredev->detectmode_handler(coredev->context,
846 &coredev->mode);
847
848 if (coredev->mode != mode && coredev->setmode_handler)
849 rc = coredev->setmode_handler(coredev->context, mode);
850 }
851
852 if (rc >= 0) {
853 coredev->mode = mode;
854 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
855 }
856
857 if (rc != 0)
858 sms_err("return error code %d.", rc);
859 return rc;
860}
861
862/**
863 * calls device handler to get current mode of operation
864 *
865 * @param coredev pointer to a coredev object returned by
866 * smscore_register_device
867 *
868 * @return current mode
869 */
870int smscore_get_device_mode(struct smscore_device_t *coredev)
871{
872 return coredev->mode;
873}
874
875/**
876 * find client by response id & type within the clients list.
877 * return client handle or NULL.
878 *
879 * @param coredev pointer to a coredev object returned by
880 * smscore_register_device
881 * @param data_type client data type (SMS_DONT_CARE for all types)
882 * @param id client id (SMS_DONT_CARE for all id)
883 *
884 */
885static struct
886smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
887 int data_type, int id)
888{
889 struct smscore_client_t *client = NULL;
890 struct list_head *next, *first;
891 unsigned long flags;
892 struct list_head *firstid, *nextid;
893
894
895 spin_lock_irqsave(&coredev->clientslock, flags);
896 first = &coredev->clients;
897 for (next = first->next;
898 (next != first) && !client;
899 next = next->next) {
900 firstid = &((struct smscore_client_t *)next)->idlist;
901 for (nextid = firstid->next;
902 nextid != firstid;
903 nextid = nextid->next) {
904 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
905 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
906 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
907 client = (struct smscore_client_t *) next;
908 break;
909 }
910 }
911 }
912 spin_unlock_irqrestore(&coredev->clientslock, flags);
913 return client;
914}
915
916/**
917 * find client by response id/type, call clients onresponse handler
918 * return buffer to pool on error
919 *
920 * @param coredev pointer to a coredev object returned by
921 * smscore_register_device
922 * @param cb pointer to response buffer descriptor
923 *
924 */
925void smscore_onresponse(struct smscore_device_t *coredev,
926 struct smscore_buffer_t *cb)
927{
928 struct SmsMsgHdr_ST *phdr =
929 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
930 struct smscore_client_t *client =
931 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
932 int rc = -EBUSY;
933
934 static unsigned long last_sample_time; /* = 0; */
935 static int data_total; /* = 0; */
936 unsigned long time_now = jiffies_to_msecs(jiffies);
937
938 if (!last_sample_time)
939 last_sample_time = time_now;
940
941 if (time_now - last_sample_time > 10000) {
942 sms_debug("\ndata rate %d bytes/secs",
943 (int)((data_total * 1000) /
944 (time_now - last_sample_time)));
945
946 last_sample_time = time_now;
947 data_total = 0;
948 }
949
950 data_total += cb->size;
951 /* If no client registered for type & id,
952 * check for control client where type is not registered */
953 if (client)
954 rc = client->onresponse_handler(client->context, cb);
955
956 if (rc < 0) {
957 switch (phdr->msgType) {
958 case MSG_SMS_GET_VERSION_EX_RES:
959 {
960 struct SmsVersionRes_ST *ver =
961 (struct SmsVersionRes_ST *) phdr;
962 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
963 "id %d prots 0x%x ver %d.%d",
964 ver->FirmwareId, ver->SupportedProtocols,
965 ver->RomVersionMajor, ver->RomVersionMinor);
966
967 coredev->mode = ver->FirmwareId == 255 ?
968 DEVICE_MODE_NONE : ver->FirmwareId;
969 coredev->modes_supported = ver->SupportedProtocols;
970
971 complete(&coredev->version_ex_done);
972 break;
973 }
974 case MSG_SMS_INIT_DEVICE_RES:
975 sms_debug("MSG_SMS_INIT_DEVICE_RES");
976 complete(&coredev->init_device_done);
977 break;
978 case MSG_SW_RELOAD_START_RES:
979 sms_debug("MSG_SW_RELOAD_START_RES");
980 complete(&coredev->reload_start_done);
981 break;
982 case MSG_SMS_DATA_DOWNLOAD_RES:
983 complete(&coredev->data_download_done);
984 break;
985 case MSG_SW_RELOAD_EXEC_RES:
986 sms_debug("MSG_SW_RELOAD_EXEC_RES");
987 break;
988 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
989 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
990 complete(&coredev->trigger_done);
991 break;
992 case MSG_SMS_SLEEP_RESUME_COMP_IND:
993 complete(&coredev->resume_done);
994 break;
995 default:
996 break;
997 }
998 smscore_putbuffer(coredev, cb);
999 }
1000}
1001
1002/**
1003 * return pointer to next free buffer descriptor from core pool
1004 *
1005 * @param coredev pointer to a coredev object returned by
1006 * smscore_register_device
1007 *
1008 * @return pointer to descriptor on success, NULL on error.
1009 */
1010struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1011{
1012 struct smscore_buffer_t *cb = NULL;
1013 unsigned long flags;
1014
1015 spin_lock_irqsave(&coredev->bufferslock, flags);
1016
1017 if (!list_empty(&coredev->buffers)) {
1018 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1019 list_del(&cb->entry);
1020 }
1021
1022 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1023
1024 return cb;
1025}
1026
1027/**
1028 * return buffer descriptor to a pool
1029 *
1030 * @param coredev pointer to a coredev object returned by
1031 * smscore_register_device
1032 * @param cb pointer buffer descriptor
1033 *
1034 */
1035void smscore_putbuffer(struct smscore_device_t *coredev,
1036 struct smscore_buffer_t *cb)
1037{
1038 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1039}
1040
1041static int smscore_validate_client(struct smscore_device_t *coredev,
1042 struct smscore_client_t *client,
1043 int data_type, int id)
1044{
1045 struct smscore_idlist_t *listentry;
1046 struct smscore_client_t *registered_client;
1047
1048 if (!client) {
1049 sms_err("bad parameter.");
1050 return -EFAULT;
1051 }
1052 registered_client = smscore_find_client(coredev, data_type, id);
1053 if (registered_client == client)
1054 return 0;
1055
1056 if (registered_client) {
1057 sms_err("The msg ID already registered to another client.");
1058 return -EEXIST;
1059 }
1060 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1061 if (!listentry) {
1062 sms_err("Can't allocate memory for client id.");
1063 return -ENOMEM;
1064 }
1065 listentry->id = id;
1066 listentry->data_type = data_type;
1067 list_add_locked(&listentry->entry, &client->idlist,
1068 &coredev->clientslock);
1069 return 0;
1070}
1071
1072/**
1073 * creates smsclient object, check that id is taken by another client
1074 *
1075 * @param coredev pointer to a coredev object from clients hotplug
1076 * @param initial_id all messages with this id would be sent to this client
1077 * @param data_type all messages of this type would be sent to this client
1078 * @param onresponse_handler client handler that is called to
1079 * process incoming messages
1080 * @param onremove_handler client handler that is called when device is removed
1081 * @param context client-specific context
1082 * @param client pointer to a value that receives created smsclient object
1083 *
1084 * @return 0 on success, <0 on error.
1085 */
1086int smscore_register_client(struct smscore_device_t *coredev,
1087 struct smsclient_params_t *params,
1088 struct smscore_client_t **client)
1089{
1090 struct smscore_client_t *newclient;
1091 /* check that no other channel with same parameters exists */
1092 if (smscore_find_client(coredev, params->data_type,
1093 params->initial_id)) {
1094 sms_err("Client already exist.");
1095 return -EEXIST;
1096 }
1097
1098 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1099 if (!newclient) {
1100 sms_err("Failed to allocate memory for client.");
1101 return -ENOMEM;
1102 }
1103
1104 INIT_LIST_HEAD(&newclient->idlist);
1105 newclient->coredev = coredev;
1106 newclient->onresponse_handler = params->onresponse_handler;
1107 newclient->onremove_handler = params->onremove_handler;
1108 newclient->context = params->context;
1109 list_add_locked(&newclient->entry, &coredev->clients,
1110 &coredev->clientslock);
1111 smscore_validate_client(coredev, newclient, params->data_type,
1112 params->initial_id);
1113 *client = newclient;
1114 sms_debug("%p %d %d", params->context, params->data_type,
1115 params->initial_id);
1116
1117 return 0;
1118}
1119
1120/**
1121 * frees smsclient object and all subclients associated with it
1122 *
1123 * @param client pointer to smsclient object returned by
1124 * smscore_register_client
1125 *
1126 */
1127void smscore_unregister_client(struct smscore_client_t *client)
1128{
1129 struct smscore_device_t *coredev = client->coredev;
1130 unsigned long flags;
1131
1132 spin_lock_irqsave(&coredev->clientslock, flags);
1133
1134
1135 while (!list_empty(&client->idlist)) {
1136 struct smscore_idlist_t *identry =
1137 (struct smscore_idlist_t *) client->idlist.next;
1138 list_del(&identry->entry);
1139 kfree(identry);
1140 }
1141
1142 sms_info("%p", client->context);
1143
1144 list_del(&client->entry);
1145 kfree(client);
1146
1147 spin_unlock_irqrestore(&coredev->clientslock, flags);
1148}
1149
1150/**
1151 * verifies that source id is not taken by another client,
1152 * calls device handler to send requests to the device
1153 *
1154 * @param client pointer to smsclient object returned by
1155 * smscore_register_client
1156 * @param buffer pointer to a request buffer
1157 * @param size size (in bytes) of request buffer
1158 *
1159 * @return 0 on success, <0 on error.
1160 */
1161int smsclient_sendrequest(struct smscore_client_t *client,
1162 void *buffer, size_t size)
1163{
1164 struct smscore_device_t *coredev;
1165 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1166 int rc;
1167
1168 if (client == NULL) {
1169 sms_err("Got NULL client");
1170 return -EINVAL;
1171 }
1172
1173 coredev = client->coredev;
1174
1175 /* check that no other channel with same id exists */
1176 if (coredev == NULL) {
1177 sms_err("Got NULL coredev");
1178 return -EINVAL;
1179 }
1180
1181 rc = smscore_validate_client(client->coredev, client, 0,
1182 phdr->msgSrcId);
1183 if (rc < 0)
1184 return rc;
1185
1186 return coredev->sendrequest_handler(coredev->context, buffer, size);
1187}
1188
1189
1190int smscore_module_init(void)
1191{
1192 int rc = 0;
1193
1194 INIT_LIST_HEAD(&g_smscore_notifyees);
1195 INIT_LIST_HEAD(&g_smscore_devices);
1196 kmutex_init(&g_smscore_deviceslock);
1197
1198 INIT_LIST_HEAD(&g_smscore_registry);
1199 kmutex_init(&g_smscore_registrylock);
1200
1201 /* USB Register */
1202 rc = smsusb_register();
1203
1204 /* DVB Register */
1205 rc = smsdvb_register();
1206
1207 sms_debug("rc %d", rc);
1208
1209 return rc;
1210}
1211
1212void smscore_module_exit(void)
1213{
1214
1215 kmutex_lock(&g_smscore_deviceslock);
1216 while (!list_empty(&g_smscore_notifyees)) {
1217 struct smscore_device_notifyee_t *notifyee =
1218 (struct smscore_device_notifyee_t *)
1219 g_smscore_notifyees.next;
1220
1221 list_del(&notifyee->entry);
1222 kfree(notifyee);
1223 }
1224 kmutex_unlock(&g_smscore_deviceslock);
1225
1226 kmutex_lock(&g_smscore_registrylock);
1227 while (!list_empty(&g_smscore_registry)) {
1228 struct smscore_registry_entry_t *entry =
1229 (struct smscore_registry_entry_t *)
1230 g_smscore_registry.next;
1231
1232 list_del(&entry->entry);
1233 kfree(entry);
1234 }
1235 kmutex_unlock(&g_smscore_registrylock);
1236
1237 /* DVB UnRegister */
1238 smsdvb_unregister();
1239
1240 /* Unregister USB */
1241 smsusb_unregister();
1242
1243 sms_debug("");
1244}
1245
1246module_init(smscore_module_init);
1247module_exit(smscore_module_exit);
1248
1249MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
1250MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1251MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
new file mode 100644
index 000000000000..c1f8f1dccb11
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -0,0 +1,434 @@
1/*
2 * Driver for the Siano SMS1xxx USB dongle
3 *
4 * author: Anatoly Greenblat
5 *
6 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 3 as
10 * published by the Free Software Foundation;
11 *
12 * Software distributed under the License is distributed on an "AS IS"
13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
14 *
15 * See the 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, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef __smscoreapi_h__
23#define __smscoreapi_h__
24
25#include <linux/version.h>
26#include <linux/device.h>
27#include <linux/list.h>
28#include <linux/mm.h>
29#include <linux/scatterlist.h>
30#include <linux/types.h>
31#include <asm/page.h>
32
33#include "dmxdev.h"
34#include "dvbdev.h"
35#include "dvb_demux.h"
36#include "dvb_frontend.h"
37
38#include <linux/mutex.h>
39
40#define kmutex_init(_p_) mutex_init(_p_)
41#define kmutex_lock(_p_) mutex_lock(_p_)
42#define kmutex_trylock(_p_) mutex_trylock(_p_)
43#define kmutex_unlock(_p_) mutex_unlock(_p_)
44
45#ifndef min
46#define min(a, b) (((a) < (b)) ? (a) : (b))
47#endif
48
49#define SMS_ALLOC_ALIGNMENT 128
50#define SMS_DMA_ALIGNMENT 16
51#define SMS_ALIGN_ADDRESS(addr) \
52 ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
53
54#define SMS_DEVICE_FAMILY2 1
55#define SMS_ROM_NO_RESPONSE 2
56#define SMS_DEVICE_NOT_READY 0x8000000
57
58enum sms_device_type_st {
59 SMS_STELLAR = 0,
60 SMS_NOVA_A0,
61 SMS_NOVA_B0,
62 SMS_VEGA,
63 SMS_NUM_OF_DEVICE_TYPES
64};
65
66struct smscore_device_t;
67struct smscore_client_t;
68struct smscore_buffer_t;
69
70typedef int (*hotplug_t)(struct smscore_device_t *coredev,
71 struct device *device, int arrival);
72
73typedef int (*setmode_t)(void *context, int mode);
74typedef void (*detectmode_t)(void *context, int *mode);
75typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
76typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
77typedef int (*preload_t)(void *context);
78typedef int (*postload_t)(void *context);
79
80typedef int (*onresponse_t)(void *context, struct smscore_buffer_t *cb);
81typedef void (*onremove_t)(void *context);
82
83struct smscore_buffer_t {
84 /* public members, once passed to clients can be changed freely */
85 struct list_head entry;
86 int size;
87 int offset;
88
89 /* private members, read-only for clients */
90 void *p;
91 dma_addr_t phys;
92 unsigned long offset_in_common;
93};
94
95struct smsdevice_params_t {
96 struct device *device;
97
98 int buffer_size;
99 int num_buffers;
100
101 char devpath[32];
102 unsigned long flags;
103
104 setmode_t setmode_handler;
105 detectmode_t detectmode_handler;
106 sendrequest_t sendrequest_handler;
107 preload_t preload_handler;
108 postload_t postload_handler;
109
110 void *context;
111 enum sms_device_type_st device_type;
112};
113
114struct smsclient_params_t {
115 int initial_id;
116 int data_type;
117 onresponse_t onresponse_handler;
118 onremove_t onremove_handler;
119
120 void *context;
121};
122
123/* GPIO definitions for antenna frequency domain control (SMS8021) */
124#define SMS_ANTENNA_GPIO_0 1
125#define SMS_ANTENNA_GPIO_1 0
126
127#define BW_8_MHZ 0
128#define BW_7_MHZ 1
129#define BW_6_MHZ 2
130#define BW_5_MHZ 3
131#define BW_ISDBT_1SEG 4
132#define BW_ISDBT_3SEG 5
133
134#define MSG_HDR_FLAG_SPLIT_MSG 4
135
136#define MAX_GPIO_PIN_NUMBER 31
137
138#define HIF_TASK 11
139#define SMS_HOST_LIB 150
140#define DVBT_BDA_CONTROL_MSG_ID 201
141
142#define SMS_MAX_PAYLOAD_SIZE 240
143#define SMS_TUNE_TIMEOUT 500
144
145#define MSG_SMS_GPIO_CONFIG_REQ 507
146#define MSG_SMS_GPIO_CONFIG_RES 508
147#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
148#define MSG_SMS_GPIO_SET_LEVEL_RES 510
149#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
150#define MSG_SMS_GPIO_GET_LEVEL_RES 512
151#define MSG_SMS_RF_TUNE_REQ 561
152#define MSG_SMS_RF_TUNE_RES 562
153#define MSG_SMS_INIT_DEVICE_REQ 578
154#define MSG_SMS_INIT_DEVICE_RES 579
155#define MSG_SMS_ADD_PID_FILTER_REQ 601
156#define MSG_SMS_ADD_PID_FILTER_RES 602
157#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
158#define MSG_SMS_REMOVE_PID_FILTER_RES 604
159#define MSG_SMS_DAB_CHANNEL 607
160#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
161#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
162#define MSG_SMS_GET_STATISTICS_REQ 615
163#define MSG_SMS_GET_STATISTICS_RES 616
164#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
165#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
166#define MSG_SMS_GET_STATISTICS_EX_REQ 653
167#define MSG_SMS_GET_STATISTICS_EX_RES 654
168#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
169#define MSG_SMS_DATA_DOWNLOAD_REQ 660
170#define MSG_SMS_DATA_DOWNLOAD_RES 661
171#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
172#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
173#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
174#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
175#define MSG_SMS_GET_VERSION_EX_REQ 668
176#define MSG_SMS_GET_VERSION_EX_RES 669
177#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
178#define MSG_SMS_I2C_SET_FREQ_REQ 685
179#define MSG_SMS_GENERIC_I2C_REQ 687
180#define MSG_SMS_GENERIC_I2C_RES 688
181#define MSG_SMS_DVBT_BDA_DATA 693
182#define MSG_SW_RELOAD_REQ 697
183#define MSG_SMS_DATA_MSG 699
184#define MSG_SW_RELOAD_START_REQ 702
185#define MSG_SW_RELOAD_START_RES 703
186#define MSG_SW_RELOAD_EXEC_REQ 704
187#define MSG_SW_RELOAD_EXEC_RES 705
188#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
189#define MSG_SMS_ISDBT_TUNE_REQ 776
190#define MSG_SMS_ISDBT_TUNE_RES 777
191
192#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
193 (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
194 (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
195} while (0)
196#define SMS_INIT_MSG(ptr, type, len) \
197 SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
198
199enum SMS_DEVICE_MODE {
200 DEVICE_MODE_NONE = -1,
201 DEVICE_MODE_DVBT = 0,
202 DEVICE_MODE_DVBH,
203 DEVICE_MODE_DAB_TDMB,
204 DEVICE_MODE_DAB_TDMB_DABIP,
205 DEVICE_MODE_DVBT_BDA,
206 DEVICE_MODE_ISDBT,
207 DEVICE_MODE_ISDBT_BDA,
208 DEVICE_MODE_CMMB,
209 DEVICE_MODE_RAW_TUNER,
210 DEVICE_MODE_MAX,
211};
212
213struct SmsMsgHdr_ST {
214 u16 msgType;
215 u8 msgSrcId;
216 u8 msgDstId;
217 u16 msgLength; /* Length of entire message, including header */
218 u16 msgFlags;
219};
220
221struct SmsMsgData_ST {
222 struct SmsMsgHdr_ST xMsgHeader;
223 u32 msgData[1];
224};
225
226struct SmsDataDownload_ST {
227 struct SmsMsgHdr_ST xMsgHeader;
228 u32 MemAddr;
229 u8 Payload[SMS_MAX_PAYLOAD_SIZE];
230};
231
232struct SmsVersionRes_ST {
233 struct SmsMsgHdr_ST xMsgHeader;
234
235 u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */
236 u8 Step; /* 0 - Step A */
237 u8 MetalFix; /* 0 - Metal 0 */
238
239 u8 FirmwareId; /* 0xFF � ROM, otherwise the
240 * value indicated by
241 * SMSHOSTLIB_DEVICE_MODES_E */
242 u8 SupportedProtocols; /* Bitwise OR combination of
243 * supported protocols */
244
245 u8 VersionMajor;
246 u8 VersionMinor;
247 u8 VersionPatch;
248 u8 VersionFieldPatch;
249
250 u8 RomVersionMajor;
251 u8 RomVersionMinor;
252 u8 RomVersionPatch;
253 u8 RomVersionFieldPatch;
254
255 u8 TextLabel[34];
256};
257
258struct SmsFirmware_ST {
259 u32 CheckSum;
260 u32 Length;
261 u32 StartAddress;
262 u8 Payload[1];
263};
264
265struct SMSHOSTLIB_STATISTICS_ST {
266 u32 Reserved; /* Reserved */
267
268 /* Common parameters */
269 u32 IsRfLocked; /* 0 - not locked, 1 - locked */
270 u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
271 u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
272
273 /* Reception quality */
274 s32 SNR; /* dB */
275 u32 BER; /* Post Viterbi BER [1E-5] */
276 u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */
277 u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
278 * valid only for DVB-T/H */
279 u32 MFER; /* DVB-H frame error rate in percentage,
280 * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
281 s32 RSSI; /* dBm */
282 s32 InBandPwr; /* In band power in dBM */
283 s32 CarrierOffset; /* Carrier Offset in bin/1024 */
284
285 /* Transmission parameters, valid only for DVB-T/H */
286 u32 Frequency; /* Frequency in Hz */
287 u32 Bandwidth; /* Bandwidth in MHz */
288 u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
289 * for DVB-T/H FFT mode carriers in Kilos */
290 u32 ModemState; /* from SMS_DvbModemState_ET */
291 u32 GuardInterval; /* Guard Interval, 1 divided by value */
292 u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
293 u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
294 u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
295 u32 Constellation; /* Constellation from SMS_Constellation_ET */
296
297 /* Burst parameters, valid only for DVB-H */
298 u32 BurstSize; /* Current burst size in bytes */
299 u32 BurstDuration; /* Current burst duration in mSec */
300 u32 BurstCycleTime; /* Current burst cycle time in mSec */
301 u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
302 * as calculated by demodulator */
303 u32 NumOfRows; /* Number of rows in MPE table */
304 u32 NumOfPaddCols; /* Number of padding columns in MPE table */
305 u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
306 /* Burst parameters */
307 u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
308 u32 TotalTSPackets; /* Total number of transport-stream packets */
309 u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
310 * errors after MPE RS decoding */
311 u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
312 * after MPE RS decoding */
313 u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
314 * by MPE RS decoding */
315
316 /* Common params */
317 u32 BERErrorCount; /* Number of errornous SYNC bits. */
318 u32 BERBitCount; /* Total number of SYNC bits. */
319
320 /* Interface information */
321 u32 SmsToHostTxErrors; /* Total number of transmission errors. */
322
323 /* DAB/T-DMB */
324 u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
325
326 /* DVB-H TPS parameters */
327 u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
328 * if set to 0xFFFFFFFF cell_id not yet recovered */
329
330};
331
332struct SmsMsgStatisticsInfo_ST {
333 u32 RequestResult;
334
335 struct SMSHOSTLIB_STATISTICS_ST Stat;
336
337 /* Split the calc of the SNR in DAB */
338 u32 Signal; /* dB */
339 u32 Noise; /* dB */
340
341};
342
343
344struct smsdvb_client_t {
345 struct list_head entry;
346
347 struct smscore_device_t *coredev;
348 struct smscore_client_t *smsclient;
349
350 struct dvb_adapter adapter;
351 struct dvb_demux demux;
352 struct dmxdev dmxdev;
353 struct dvb_frontend frontend;
354
355 fe_status_t fe_status;
356 int fe_ber, fe_snr, fe_signal_strength;
357
358 struct completion tune_done, stat_done;
359
360 /* todo: save freq/band instead whole struct */
361 struct dvb_frontend_parameters fe_params;
362
363};
364
365extern void smscore_registry_setmode(char *devpath, int mode);
366extern int smscore_registry_getmode(char *devpath);
367
368extern int smscore_register_hotplug(hotplug_t hotplug);
369extern void smscore_unregister_hotplug(hotplug_t hotplug);
370
371extern int smscore_register_device(struct smsdevice_params_t *params,
372 struct smscore_device_t **coredev);
373extern void smscore_unregister_device(struct smscore_device_t *coredev);
374
375extern int smscore_start_device(struct smscore_device_t *coredev);
376extern int smscore_load_firmware(struct smscore_device_t *coredev,
377 char *filename,
378 loadfirmware_t loadfirmware_handler);
379
380extern int smscore_set_device_mode(struct smscore_device_t *coredev, int mode);
381extern int smscore_get_device_mode(struct smscore_device_t *coredev);
382
383extern int smscore_register_client(struct smscore_device_t *coredev,
384 struct smsclient_params_t *params,
385 struct smscore_client_t **client);
386extern void smscore_unregister_client(struct smscore_client_t *client);
387
388extern int smsclient_sendrequest(struct smscore_client_t *client,
389 void *buffer, size_t size);
390extern void smscore_onresponse(struct smscore_device_t *coredev,
391 struct smscore_buffer_t *cb);
392
393
394extern
395struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
396extern void smscore_putbuffer(struct smscore_device_t *coredev,
397 struct smscore_buffer_t *cb);
398
399void smscore_set_board_id(struct smscore_device_t *core, int id);
400int smscore_get_board_id(struct smscore_device_t *core);
401
402/* smsdvb.c */
403int smsdvb_register(void);
404void smsdvb_unregister(void);
405
406/* smsusb.c */
407int smsusb_register(void);
408void smsusb_unregister(void);
409
410/* ------------------------------------------------------------------------ */
411
412extern int sms_debug;
413
414#define DBG_INFO 1
415#define DBG_ADV 2
416
417#define sms_printk(kern, fmt, arg...) \
418 printk(kern "%s: " fmt "\n", __func__, ##arg)
419
420#define dprintk(kern, lvl, fmt, arg...) do {\
421 if (sms_debug & lvl) \
422 sms_printk(kern, fmt, ##arg); } while (0)
423
424#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg)
425#define sms_err(fmt, arg...) \
426 sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg)
427#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg)
428#define sms_info(fmt, arg...) \
429 dprintk(KERN_INFO, DBG_INFO, fmt, ##arg)
430#define sms_debug(fmt, arg...) \
431 dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
432
433
434#endif /* __smscoreapi_h__ */
diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c
new file mode 100644
index 000000000000..6f9c18563867
--- /dev/null
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -0,0 +1,449 @@
1/*
2 * Driver for the Siano SMS1xxx USB dongle
3 *
4 * author: Anatoly Greenblat
5 *
6 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 3 as
10 * published by the Free Software Foundation;
11 *
12 * Software distributed under the License is distributed on an "AS IS"
13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
14 *
15 * See the 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, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/init.h>
24
25#include "smscoreapi.h"
26#include "sms-cards.h"
27
28DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
29
30struct list_head g_smsdvb_clients;
31struct mutex g_smsdvb_clientslock;
32
33static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
34{
35 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
36 struct SmsMsgHdr_ST *phdr =
37 (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
38
39 switch (phdr->msgType) {
40 case MSG_SMS_DVBT_BDA_DATA:
41 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
42 cb->size - sizeof(struct SmsMsgHdr_ST));
43 break;
44
45 case MSG_SMS_RF_TUNE_RES:
46 complete(&client->tune_done);
47 break;
48
49 case MSG_SMS_GET_STATISTICS_RES:
50 {
51 struct SmsMsgStatisticsInfo_ST *p =
52 (struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
53
54 if (p->Stat.IsDemodLocked) {
55 client->fe_status = FE_HAS_SIGNAL |
56 FE_HAS_CARRIER |
57 FE_HAS_VITERBI |
58 FE_HAS_SYNC |
59 FE_HAS_LOCK;
60
61 client->fe_snr = p->Stat.SNR;
62 client->fe_ber = p->Stat.BER;
63
64 if (p->Stat.InBandPwr < -95)
65 client->fe_signal_strength = 0;
66 else if (p->Stat.InBandPwr > -29)
67 client->fe_signal_strength = 100;
68 else
69 client->fe_signal_strength =
70 (p->Stat.InBandPwr + 95) * 3 / 2;
71 } else {
72 client->fe_status = 0;
73 client->fe_snr =
74 client->fe_ber =
75 client->fe_signal_strength = 0;
76 }
77
78 complete(&client->stat_done);
79 break;
80 } }
81
82 smscore_putbuffer(client->coredev, cb);
83
84 return 0;
85}
86
87static void smsdvb_unregister_client(struct smsdvb_client_t *client)
88{
89 /* must be called under clientslock */
90
91 list_del(&client->entry);
92
93 smscore_unregister_client(client->smsclient);
94 dvb_unregister_frontend(&client->frontend);
95 dvb_dmxdev_release(&client->dmxdev);
96 dvb_dmx_release(&client->demux);
97 dvb_unregister_adapter(&client->adapter);
98 kfree(client);
99}
100
101static void smsdvb_onremove(void *context)
102{
103 kmutex_lock(&g_smsdvb_clientslock);
104
105 smsdvb_unregister_client((struct smsdvb_client_t *) context);
106
107 kmutex_unlock(&g_smsdvb_clientslock);
108}
109
110static int smsdvb_start_feed(struct dvb_demux_feed *feed)
111{
112 struct smsdvb_client_t *client =
113 container_of(feed->demux, struct smsdvb_client_t, demux);
114 struct SmsMsgData_ST PidMsg;
115
116 sms_debug("add pid %d(%x)",
117 feed->pid, feed->pid);
118
119 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
120 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
121 PidMsg.xMsgHeader.msgFlags = 0;
122 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
123 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
124 PidMsg.msgData[0] = feed->pid;
125
126 return smsclient_sendrequest(client->smsclient,
127 &PidMsg, sizeof(PidMsg));
128}
129
130static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
131{
132 struct smsdvb_client_t *client =
133 container_of(feed->demux, struct smsdvb_client_t, demux);
134 struct SmsMsgData_ST PidMsg;
135
136 sms_debug("remove pid %d(%x)",
137 feed->pid, feed->pid);
138
139 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
140 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
141 PidMsg.xMsgHeader.msgFlags = 0;
142 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
143 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
144 PidMsg.msgData[0] = feed->pid;
145
146 return smsclient_sendrequest(client->smsclient,
147 &PidMsg, sizeof(PidMsg));
148}
149
150static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
151 void *buffer, size_t size,
152 struct completion *completion)
153{
154 int rc = smsclient_sendrequest(client->smsclient, buffer, size);
155 if (rc < 0)
156 return rc;
157
158 return wait_for_completion_timeout(completion,
159 msecs_to_jiffies(2000)) ?
160 0 : -ETIME;
161}
162
163static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
164{
165 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
166 DVBT_BDA_CONTROL_MSG_ID,
167 HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
168 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
169 &client->stat_done);
170}
171
172static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
173{
174 struct smsdvb_client_t *client =
175 container_of(fe, struct smsdvb_client_t, frontend);
176 int rc = smsdvb_send_statistics_request(client);
177
178 if (!rc)
179 *stat = client->fe_status;
180
181 return rc;
182}
183
184static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
185{
186 struct smsdvb_client_t *client =
187 container_of(fe, struct smsdvb_client_t, frontend);
188 int rc = smsdvb_send_statistics_request(client);
189
190 if (!rc)
191 *ber = client->fe_ber;
192
193 return rc;
194}
195
196static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
197{
198 struct smsdvb_client_t *client =
199 container_of(fe, struct smsdvb_client_t, frontend);
200 int rc = smsdvb_send_statistics_request(client);
201
202 if (!rc)
203 *strength = client->fe_signal_strength;
204
205 return rc;
206}
207
208static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
209{
210 struct smsdvb_client_t *client =
211 container_of(fe, struct smsdvb_client_t, frontend);
212 int rc = smsdvb_send_statistics_request(client);
213
214 if (!rc)
215 *snr = client->fe_snr;
216
217 return rc;
218}
219
220static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
221 struct dvb_frontend_tune_settings *tune)
222{
223 sms_debug("");
224
225 tune->min_delay_ms = 400;
226 tune->step_size = 250000;
227 tune->max_drift = 0;
228 return 0;
229}
230
231static int smsdvb_set_frontend(struct dvb_frontend *fe,
232 struct dvb_frontend_parameters *fep)
233{
234 struct smsdvb_client_t *client =
235 container_of(fe, struct smsdvb_client_t, frontend);
236
237 struct {
238 struct SmsMsgHdr_ST Msg;
239 u32 Data[3];
240 } Msg;
241
242 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
243 Msg.Msg.msgDstId = HIF_TASK;
244 Msg.Msg.msgFlags = 0;
245 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
246 Msg.Msg.msgLength = sizeof(Msg);
247 Msg.Data[0] = fep->frequency;
248 Msg.Data[2] = 12000000;
249
250 sms_debug("freq %d band %d",
251 fep->frequency, fep->u.ofdm.bandwidth);
252
253 switch (fep->u.ofdm.bandwidth) {
254 case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
255 case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
256 case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
257 case BANDWIDTH_AUTO: return -EOPNOTSUPP;
258 default: return -EINVAL;
259 }
260
261 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
262 &client->tune_done);
263}
264
265static int smsdvb_get_frontend(struct dvb_frontend *fe,
266 struct dvb_frontend_parameters *fep)
267{
268 struct smsdvb_client_t *client =
269 container_of(fe, struct smsdvb_client_t, frontend);
270
271 sms_debug("");
272
273 /* todo: */
274 memcpy(fep, &client->fe_params,
275 sizeof(struct dvb_frontend_parameters));
276 return 0;
277}
278
279static void smsdvb_release(struct dvb_frontend *fe)
280{
281 /* do nothing */
282}
283
284static struct dvb_frontend_ops smsdvb_fe_ops = {
285 .info = {
286 .name = "Siano Mobile Digital SMS1xxx",
287 .type = FE_OFDM,
288 .frequency_min = 44250000,
289 .frequency_max = 867250000,
290 .frequency_stepsize = 250000,
291 .caps = FE_CAN_INVERSION_AUTO |
292 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
293 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
294 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
295 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
296 FE_CAN_GUARD_INTERVAL_AUTO |
297 FE_CAN_RECOVER |
298 FE_CAN_HIERARCHY_AUTO,
299 },
300
301 .release = smsdvb_release,
302
303 .set_frontend = smsdvb_set_frontend,
304 .get_frontend = smsdvb_get_frontend,
305 .get_tune_settings = smsdvb_get_tune_settings,
306
307 .read_status = smsdvb_read_status,
308 .read_ber = smsdvb_read_ber,
309 .read_signal_strength = smsdvb_read_signal_strength,
310 .read_snr = smsdvb_read_snr,
311};
312
313static int smsdvb_hotplug(struct smscore_device_t *coredev,
314 struct device *device, int arrival)
315{
316 struct smsclient_params_t params;
317 struct smsdvb_client_t *client;
318 int rc;
319
320 /* device removal handled by onremove callback */
321 if (!arrival)
322 return 0;
323
324 if (smscore_get_device_mode(coredev) != 4) {
325 sms_err("SMS Device mode is not set for "
326 "DVB operation.");
327 return 0;
328 }
329
330 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
331 if (!client) {
332 sms_err("kmalloc() failed");
333 return -ENOMEM;
334 }
335
336 /* register dvb adapter */
337 rc = dvb_register_adapter(&client->adapter,
338 sms_get_board(
339 smscore_get_board_id(coredev))->name,
340 THIS_MODULE, device, adapter_nr);
341 if (rc < 0) {
342 sms_err("dvb_register_adapter() failed %d", rc);
343 goto adapter_error;
344 }
345
346 /* init dvb demux */
347 client->demux.dmx.capabilities = DMX_TS_FILTERING;
348 client->demux.filternum = 32; /* todo: nova ??? */
349 client->demux.feednum = 32;
350 client->demux.start_feed = smsdvb_start_feed;
351 client->demux.stop_feed = smsdvb_stop_feed;
352
353 rc = dvb_dmx_init(&client->demux);
354 if (rc < 0) {
355 sms_err("dvb_dmx_init failed %d", rc);
356 goto dvbdmx_error;
357 }
358
359 /* init dmxdev */
360 client->dmxdev.filternum = 32;
361 client->dmxdev.demux = &client->demux.dmx;
362 client->dmxdev.capabilities = 0;
363
364 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
365 if (rc < 0) {
366 sms_err("dvb_dmxdev_init failed %d", rc);
367 goto dmxdev_error;
368 }
369
370 /* init and register frontend */
371 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
372 sizeof(struct dvb_frontend_ops));
373
374 rc = dvb_register_frontend(&client->adapter, &client->frontend);
375 if (rc < 0) {
376 sms_err("frontend registration failed %d", rc);
377 goto frontend_error;
378 }
379
380 params.initial_id = 1;
381 params.data_type = MSG_SMS_DVBT_BDA_DATA;
382 params.onresponse_handler = smsdvb_onresponse;
383 params.onremove_handler = smsdvb_onremove;
384 params.context = client;
385
386 rc = smscore_register_client(coredev, &params, &client->smsclient);
387 if (rc < 0) {
388 sms_err("smscore_register_client() failed %d", rc);
389 goto client_error;
390 }
391
392 client->coredev = coredev;
393
394 init_completion(&client->tune_done);
395 init_completion(&client->stat_done);
396
397 kmutex_lock(&g_smsdvb_clientslock);
398
399 list_add(&client->entry, &g_smsdvb_clients);
400
401 kmutex_unlock(&g_smsdvb_clientslock);
402
403 sms_info("success");
404
405 return 0;
406
407client_error:
408 dvb_unregister_frontend(&client->frontend);
409
410frontend_error:
411 dvb_dmxdev_release(&client->dmxdev);
412
413dmxdev_error:
414 dvb_dmx_release(&client->demux);
415
416dvbdmx_error:
417 dvb_unregister_adapter(&client->adapter);
418
419adapter_error:
420 kfree(client);
421 return rc;
422}
423
424int smsdvb_register(void)
425{
426 int rc;
427
428 INIT_LIST_HEAD(&g_smsdvb_clients);
429 kmutex_init(&g_smsdvb_clientslock);
430
431 rc = smscore_register_hotplug(smsdvb_hotplug);
432
433 sms_debug("");
434
435 return rc;
436}
437
438void smsdvb_unregister(void)
439{
440 smscore_unregister_hotplug(smsdvb_hotplug);
441
442 kmutex_lock(&g_smsdvb_clientslock);
443
444 while (!list_empty(&g_smsdvb_clients))
445 smsdvb_unregister_client(
446 (struct smsdvb_client_t *) g_smsdvb_clients.next);
447
448 kmutex_unlock(&g_smsdvb_clientslock);
449}
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
new file mode 100644
index 000000000000..c10b1849c6a3
--- /dev/null
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -0,0 +1,459 @@
1/*
2 * Driver for the Siano SMS1xxx USB dongle
3 *
4 * author: Anatoly Greenblat
5 *
6 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 3 as
10 * published by the Free Software Foundation;
11 *
12 * Software distributed under the License is distributed on an "AS IS"
13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
14 *
15 * See the 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, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/usb.h>
25#include <linux/firmware.h>
26
27#include "smscoreapi.h"
28#include "sms-cards.h"
29
30#define USB1_BUFFER_SIZE 0x1000
31#define USB2_BUFFER_SIZE 0x4000
32
33#define MAX_BUFFERS 50
34#define MAX_URBS 10
35
36struct smsusb_device_t;
37
38struct smsusb_urb_t {
39 struct smscore_buffer_t *cb;
40 struct smsusb_device_t *dev;
41
42 struct urb urb;
43};
44
45struct smsusb_device_t {
46 struct usb_device *udev;
47 struct smscore_device_t *coredev;
48
49 struct smsusb_urb_t surbs[MAX_URBS];
50
51 int response_alignment;
52 int buffer_size;
53};
54
55static int smsusb_submit_urb(struct smsusb_device_t *dev,
56 struct smsusb_urb_t *surb);
57
58static void smsusb_onresponse(struct urb *urb)
59{
60 struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
61 struct smsusb_device_t *dev = surb->dev;
62
63 if (urb->status < 0) {
64 sms_err("error, urb status %d, %d bytes",
65 urb->status, urb->actual_length);
66 return;
67 }
68
69 if (urb->actual_length > 0) {
70 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
71
72 if (urb->actual_length >= phdr->msgLength) {
73 surb->cb->size = phdr->msgLength;
74
75 if (dev->response_alignment &&
76 (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) {
77
78 surb->cb->offset =
79 dev->response_alignment +
80 ((phdr->msgFlags >> 8) & 3);
81
82 /* sanity check */
83 if (((int) phdr->msgLength +
84 surb->cb->offset) > urb->actual_length) {
85 sms_err("invalid response "
86 "msglen %d offset %d "
87 "size %d",
88 phdr->msgLength,
89 surb->cb->offset,
90 urb->actual_length);
91 goto exit_and_resubmit;
92 }
93
94 /* move buffer pointer and
95 * copy header to its new location */
96 memcpy((char *) phdr + surb->cb->offset,
97 phdr, sizeof(struct SmsMsgHdr_ST));
98 } else
99 surb->cb->offset = 0;
100
101 smscore_onresponse(dev->coredev, surb->cb);
102 surb->cb = NULL;
103 } else {
104 sms_err("invalid response "
105 "msglen %d actual %d",
106 phdr->msgLength, urb->actual_length);
107 }
108 }
109
110exit_and_resubmit:
111 smsusb_submit_urb(dev, surb);
112}
113
114static int smsusb_submit_urb(struct smsusb_device_t *dev,
115 struct smsusb_urb_t *surb)
116{
117 if (!surb->cb) {
118 surb->cb = smscore_getbuffer(dev->coredev);
119 if (!surb->cb) {
120 sms_err("smscore_getbuffer(...) returned NULL");
121 return -ENOMEM;
122 }
123 }
124
125 usb_fill_bulk_urb(
126 &surb->urb,
127 dev->udev,
128 usb_rcvbulkpipe(dev->udev, 0x81),
129 surb->cb->p,
130 dev->buffer_size,
131 smsusb_onresponse,
132 surb
133 );
134 surb->urb.transfer_dma = surb->cb->phys;
135 surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
136
137 return usb_submit_urb(&surb->urb, GFP_ATOMIC);
138}
139
140static void smsusb_stop_streaming(struct smsusb_device_t *dev)
141{
142 int i;
143
144 for (i = 0; i < MAX_URBS; i++) {
145 usb_kill_urb(&dev->surbs[i].urb);
146
147 if (dev->surbs[i].cb) {
148 smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
149 dev->surbs[i].cb = NULL;
150 }
151 }
152}
153
154static int smsusb_start_streaming(struct smsusb_device_t *dev)
155{
156 int i, rc;
157
158 for (i = 0; i < MAX_URBS; i++) {
159 rc = smsusb_submit_urb(dev, &dev->surbs[i]);
160 if (rc < 0) {
161 sms_err("smsusb_submit_urb(...) failed");
162 smsusb_stop_streaming(dev);
163 break;
164 }
165 }
166
167 return rc;
168}
169
170static int smsusb_sendrequest(void *context, void *buffer, size_t size)
171{
172 struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
173 int dummy;
174
175 return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
176 buffer, size, &dummy, 1000);
177}
178
179static char *smsusb1_fw_lkup[] = {
180 "dvbt_stellar_usb.inp",
181 "dvbh_stellar_usb.inp",
182 "tdmb_stellar_usb.inp",
183 "none",
184 "dvbt_bda_stellar_usb.inp",
185};
186
187static inline char *sms_get_fw_name(int mode, int board_id)
188{
189 char **fw = sms_get_board(board_id)->fw;
190 return (fw && fw[mode]) ? fw[mode] : smsusb1_fw_lkup[mode];
191}
192
193static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id)
194{
195 const struct firmware *fw;
196 u8 *fw_buffer;
197 int rc, dummy;
198 char *fw_filename;
199
200 if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) {
201 sms_err("invalid firmware id specified %d", id);
202 return -EINVAL;
203 }
204
205 fw_filename = sms_get_fw_name(id, board_id);
206
207 rc = request_firmware(&fw, fw_filename, &udev->dev);
208 if (rc < 0) {
209 sms_warn("failed to open \"%s\" mode %d, "
210 "trying again with default firmware", fw_filename, id);
211
212 fw_filename = smsusb1_fw_lkup[id];
213 rc = request_firmware(&fw, fw_filename, &udev->dev);
214 if (rc < 0) {
215 sms_warn("failed to open \"%s\" mode %d",
216 fw_filename, id);
217
218 return rc;
219 }
220 }
221
222 fw_buffer = kmalloc(fw->size, GFP_KERNEL);
223 if (fw_buffer) {
224 memcpy(fw_buffer, fw->data, fw->size);
225
226 rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2),
227 fw_buffer, fw->size, &dummy, 1000);
228
229 sms_info("sent %zd(%d) bytes, rc %d", fw->size, dummy, rc);
230
231 kfree(fw_buffer);
232 } else {
233 sms_err("failed to allocate firmware buffer");
234 rc = -ENOMEM;
235 }
236 sms_info("read FW %s, size=%zd", fw_filename, fw->size);
237
238 release_firmware(fw);
239
240 return rc;
241}
242
243static void smsusb1_detectmode(void *context, int *mode)
244{
245 char *product_string =
246 ((struct smsusb_device_t *) context)->udev->product;
247
248 *mode = DEVICE_MODE_NONE;
249
250 if (!product_string) {
251 product_string = "none";
252 sms_err("product string not found");
253 } else if (strstr(product_string, "DVBH"))
254 *mode = 1;
255 else if (strstr(product_string, "BDA"))
256 *mode = 4;
257 else if (strstr(product_string, "DVBT"))
258 *mode = 0;
259 else if (strstr(product_string, "TDMB"))
260 *mode = 2;
261
262 sms_info("%d \"%s\"", *mode, product_string);
263}
264
265static int smsusb1_setmode(void *context, int mode)
266{
267 struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK,
268 sizeof(struct SmsMsgHdr_ST), 0 };
269
270 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
271 sms_err("invalid firmware id specified %d", mode);
272 return -EINVAL;
273 }
274
275 return smsusb_sendrequest(context, &Msg, sizeof(Msg));
276}
277
278static void smsusb_term_device(struct usb_interface *intf)
279{
280 struct smsusb_device_t *dev =
281 (struct smsusb_device_t *) usb_get_intfdata(intf);
282
283 if (dev) {
284 smsusb_stop_streaming(dev);
285
286 /* unregister from smscore */
287 if (dev->coredev)
288 smscore_unregister_device(dev->coredev);
289
290 kfree(dev);
291
292 sms_info("device %p destroyed", dev);
293 }
294
295 usb_set_intfdata(intf, NULL);
296}
297
298static int smsusb_init_device(struct usb_interface *intf, int board_id)
299{
300 struct smsdevice_params_t params;
301 struct smsusb_device_t *dev;
302 int i, rc;
303
304 /* create device object */
305 dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL);
306 if (!dev) {
307 sms_err("kzalloc(sizeof(struct smsusb_device_t) failed");
308 return -ENOMEM;
309 }
310
311 memset(&params, 0, sizeof(params));
312 usb_set_intfdata(intf, dev);
313 dev->udev = interface_to_usbdev(intf);
314
315 params.device_type = sms_get_board(board_id)->type;
316
317 switch (params.device_type) {
318 case SMS_STELLAR:
319 dev->buffer_size = USB1_BUFFER_SIZE;
320
321 params.setmode_handler = smsusb1_setmode;
322 params.detectmode_handler = smsusb1_detectmode;
323 break;
324 default:
325 sms_err("Unspecified sms device type!");
326 /* fall-thru */
327 case SMS_NOVA_A0:
328 case SMS_NOVA_B0:
329 case SMS_VEGA:
330 dev->buffer_size = USB2_BUFFER_SIZE;
331 dev->response_alignment =
332 dev->udev->ep_in[1]->desc.wMaxPacketSize -
333 sizeof(struct SmsMsgHdr_ST);
334
335 params.flags |= SMS_DEVICE_FAMILY2;
336 break;
337 }
338
339 params.device = &dev->udev->dev;
340 params.buffer_size = dev->buffer_size;
341 params.num_buffers = MAX_BUFFERS;
342 params.sendrequest_handler = smsusb_sendrequest;
343 params.context = dev;
344 snprintf(params.devpath, sizeof(params.devpath),
345 "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
346
347 /* register in smscore */
348 rc = smscore_register_device(&params, &dev->coredev);
349 if (rc < 0) {
350 sms_err("smscore_register_device(...) failed, rc %d", rc);
351 smsusb_term_device(intf);
352 return rc;
353 }
354
355 smscore_set_board_id(dev->coredev, board_id);
356
357 /* initialize urbs */
358 for (i = 0; i < MAX_URBS; i++) {
359 dev->surbs[i].dev = dev;
360 usb_init_urb(&dev->surbs[i].urb);
361 }
362
363 sms_info("smsusb_start_streaming(...).");
364 rc = smsusb_start_streaming(dev);
365 if (rc < 0) {
366 sms_err("smsusb_start_streaming(...) failed");
367 smsusb_term_device(intf);
368 return rc;
369 }
370
371 rc = smscore_start_device(dev->coredev);
372 if (rc < 0) {
373 sms_err("smscore_start_device(...) failed");
374 smsusb_term_device(intf);
375 return rc;
376 }
377
378 sms_info("device %p created", dev);
379
380 return rc;
381}
382
383static int smsusb_probe(struct usb_interface *intf,
384 const struct usb_device_id *id)
385{
386 struct usb_device *udev = interface_to_usbdev(intf);
387 char devpath[32];
388 int i, rc;
389
390 rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81));
391 rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02));
392
393 if (intf->num_altsetting > 0) {
394 rc = usb_set_interface(
395 udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
396 if (rc < 0) {
397 sms_err("usb_set_interface failed, rc %d", rc);
398 return rc;
399 }
400 }
401
402 sms_info("smsusb_probe %d",
403 intf->cur_altsetting->desc.bInterfaceNumber);
404 for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++)
405 sms_info("endpoint %d %02x %02x %d", i,
406 intf->cur_altsetting->endpoint[i].desc.bEndpointAddress,
407 intf->cur_altsetting->endpoint[i].desc.bmAttributes,
408 intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
409
410 if ((udev->actconfig->desc.bNumInterfaces == 2) &&
411 (intf->cur_altsetting->desc.bInterfaceNumber == 0)) {
412 sms_err("rom interface 0 is not used");
413 return -ENODEV;
414 }
415
416 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
417 snprintf(devpath, sizeof(devpath), "usb\\%d-%s",
418 udev->bus->busnum, udev->devpath);
419 sms_info("stellar device was found.");
420 return smsusb1_load_firmware(
421 udev, smscore_registry_getmode(devpath),
422 id->driver_info);
423 }
424
425 rc = smsusb_init_device(intf, id->driver_info);
426 sms_info("rc %d", rc);
427 return rc;
428}
429
430static void smsusb_disconnect(struct usb_interface *intf)
431{
432 smsusb_term_device(intf);
433}
434
435static struct usb_driver smsusb_driver = {
436 .name = "sms1xxx",
437 .probe = smsusb_probe,
438 .disconnect = smsusb_disconnect,
439 .id_table = smsusb_id_table,
440};
441
442int smsusb_register(void)
443{
444 int rc = usb_register(&smsusb_driver);
445 if (rc)
446 sms_err("usb_register failed. Error number %d", rc);
447
448 sms_debug("");
449
450 return rc;
451}
452
453void smsusb_unregister(void)
454{
455 sms_debug("");
456 /* Regular USB Cleanup */
457 usb_deregister(&smsusb_driver);
458}
459