aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorMichael Krufky <mkrufky@linuxtv.org>2008-05-22 17:29:20 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-07-20 06:20:47 -0400
commit854470606070d91955f03a7dca3a8024fc2a2540 (patch)
tree858216ab89c0f23b1f6d23782b4275112550b499 /drivers/media/dvb
parent7d18d2e91b5495ed0b99c83d595a56e25521a111 (diff)
V4L/DVB (8272): sms1xxx: move driver from media/mdtv/ to media/dvb/siano/
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/Kconfig1
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/siano/Kconfig16
-rw-r--r--drivers/media/dvb/siano/Makefile8
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c1158
-rw-r--r--drivers/media/dvb/siano/smscoreapi.h531
-rw-r--r--drivers/media/dvb/siano/smsdvb.c425
-rw-r--r--drivers/media/dvb/siano/smsusb.c436
8 files changed, 2576 insertions, 1 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 7b21b49f1945..8bc1445bd33b 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -21,6 +21,7 @@ source "drivers/media/dvb/dvb-usb/Kconfig"
21source "drivers/media/dvb/ttusb-budget/Kconfig" 21source "drivers/media/dvb/ttusb-budget/Kconfig"
22source "drivers/media/dvb/ttusb-dec/Kconfig" 22source "drivers/media/dvb/ttusb-dec/Kconfig"
23source "drivers/media/dvb/cinergyT2/Kconfig" 23source "drivers/media/dvb/cinergyT2/Kconfig"
24source "drivers/media/dvb/siano/Kconfig"
24 25
25comment "Supported FlexCopII (B2C2) Adapters" 26comment "Supported FlexCopII (B2C2) Adapters"
26 depends on DVB_CORE && (PCI || USB) && I2C 27 depends on DVB_CORE && (PCI || USB) && I2C
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index a7ad0841e6fc..d6ba4d195201 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
2# Makefile for the kernel multimedia device drivers. 2# Makefile for the kernel multimedia device drivers.
3# 3#
4 4
5obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ 5obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/ siano/
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
new file mode 100644
index 000000000000..878d48c1cfc0
--- /dev/null
+++ b/drivers/media/dvb/siano/Kconfig
@@ -0,0 +1,16 @@
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 USB dongle with SMS1xxx chipset.
10
11 Further documentation on this driver can be found on the WWW at
12 <http://www.siano-ms.com/>.
13
14 To compile this driver as a module, choose M here: the
15 module will be called sms1xxx.
16
diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile
new file mode 100644
index 000000000000..e549c4e2bbe2
--- /dev/null
+++ b/drivers/media/dvb/siano/Makefile
@@ -0,0 +1,8 @@
1sms1xxx-objs := smscoreapi.o smsusb.o smsdvb.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/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
new file mode 100644
index 000000000000..d3ba1fcde54a
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -0,0 +1,1158 @@
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 <asm/io.h>
31
32#include <linux/firmware.h>
33
34#include "smscoreapi.h"
35
36typedef struct _smscore_device_notifyee
37{
38 struct list_head entry;
39 hotplug_t hotplug;
40} smscore_device_notifyee_t;
41
42typedef struct _smscore_client
43{
44 struct list_head entry;
45 smscore_device_t *coredev;
46
47 void *context;
48
49 int data_type;
50
51 onresponse_t onresponse_handler;
52 onremove_t onremove_handler;
53} *psmscore_client_t;
54
55typedef struct _smscore_subclient
56{
57 struct list_head entry;
58 smscore_client_t *client;
59
60 int id;
61} smscore_subclient_t;
62
63typedef struct _smscore_device
64{
65 struct list_head entry;
66
67 struct list_head clients;
68 struct list_head subclients;
69 spinlock_t clientslock;
70
71 struct list_head buffers;
72 spinlock_t bufferslock;
73 int num_buffers;
74
75 void *common_buffer;
76 int common_buffer_size;
77 dma_addr_t common_buffer_phys;
78
79 void *context;
80 struct device *device;
81
82 char devpath[32];
83 unsigned long device_flags;
84
85 setmode_t setmode_handler;
86 detectmode_t detectmode_handler;
87 sendrequest_t sendrequest_handler;
88 preload_t preload_handler;
89 postload_t postload_handler;
90
91 int mode, modes_supported;
92
93 struct completion version_ex_done, data_download_done, trigger_done;
94 struct completion init_device_done, reload_start_done, resume_done;
95} *psmscore_device_t;
96
97typedef struct _smscore_registry_entry
98{
99 struct list_head entry;
100 char devpath[32];
101 int mode;
102} smscore_registry_entry_t;
103
104struct list_head g_smscore_notifyees;
105struct list_head g_smscore_devices;
106kmutex_t g_smscore_deviceslock;
107
108struct list_head g_smscore_registry;
109kmutex_t g_smscore_registrylock;
110
111static int default_mode = 1;
112module_param(default_mode, int, 0644);
113MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
114
115int smscore_registry_getmode(char* devpath)
116{
117 smscore_registry_entry_t *entry;
118 struct list_head *next;
119
120 kmutex_lock(&g_smscore_registrylock);
121
122 for (next = g_smscore_registry.next; next != &g_smscore_registry; next = next->next)
123 {
124 entry = (smscore_registry_entry_t *) next;
125
126 if (!strcmp(entry->devpath, devpath))
127 {
128 kmutex_unlock(&g_smscore_registrylock);
129 return entry->mode;
130 }
131 }
132
133 entry = (smscore_registry_entry_t *) kmalloc(sizeof(smscore_registry_entry_t), GFP_KERNEL);
134 if (entry)
135 {
136 entry->mode = default_mode;
137 strcpy(entry->devpath, devpath);
138
139 list_add(&entry->entry, &g_smscore_registry);
140 }
141
142 kmutex_unlock(&g_smscore_registrylock);
143
144 return default_mode;
145}
146
147void smscore_registry_setmode(char* devpath, int mode)
148{
149 smscore_registry_entry_t *entry;
150 struct list_head *next;
151
152 kmutex_lock(&g_smscore_registrylock);
153
154 for (next = g_smscore_registry.next; next != &g_smscore_registry; next = next->next)
155 {
156 entry = (smscore_registry_entry_t *) next;
157
158 if (!strcmp(entry->devpath, devpath))
159 {
160 entry->mode = mode;
161 break;
162 }
163 }
164
165 kmutex_unlock(&g_smscore_registrylock);
166}
167
168
169void list_add_locked(struct list_head *new, struct list_head *head, spinlock_t* lock)
170{
171 unsigned long flags;
172
173 spin_lock_irqsave(lock, flags);
174
175 list_add(new, head);
176
177 spin_unlock_irqrestore(lock, flags);
178}
179
180/**
181 * register a client callback that called when device plugged in/unplugged
182 * NOTE: if devices exist callback is called immediately for each device
183 *
184 * @param hotplug callback
185 *
186 * @return 0 on success, <0 on error.
187 */
188int smscore_register_hotplug(hotplug_t hotplug)
189{
190 smscore_device_notifyee_t *notifyee;
191 struct list_head *next, *first;
192 int rc = 0;
193
194 kmutex_lock(&g_smscore_deviceslock);
195
196 notifyee = kmalloc(sizeof(smscore_device_notifyee_t), GFP_KERNEL);
197 if (notifyee)
198 {
199 // now notify callback about existing devices
200 first = &g_smscore_devices;
201 for (next = first->next; next != first && !rc; next = next->next)
202 {
203 smscore_device_t *coredev = (smscore_device_t *) next;
204 rc = hotplug(coredev, coredev->device, 1);
205 }
206
207 if (rc >= 0)
208 {
209 notifyee->hotplug = hotplug;
210 list_add(&notifyee->entry, &g_smscore_notifyees);
211 }
212 else
213 kfree(notifyee);
214 }
215 else
216 rc = -ENOMEM;
217
218 kmutex_unlock(&g_smscore_deviceslock);
219
220 return rc;
221}
222
223/**
224 * unregister a client callback that called when device plugged in/unplugged
225 *
226 * @param hotplug callback
227 *
228 */
229void smscore_unregister_hotplug(hotplug_t hotplug)
230{
231 struct list_head *next, *first;
232
233 kmutex_lock(&g_smscore_deviceslock);
234
235 first = &g_smscore_notifyees;
236
237 for (next = first->next; next != first;)
238 {
239 smscore_device_notifyee_t *notifyee = (smscore_device_notifyee_t *) next;
240 next = next->next;
241
242 if (notifyee->hotplug == hotplug)
243 {
244 list_del(&notifyee->entry);
245 kfree(notifyee);
246 }
247 }
248
249 kmutex_unlock(&g_smscore_deviceslock);
250}
251
252void smscore_notify_clients(smscore_device_t *coredev)
253{
254 smscore_client_t* client;
255
256 // the client must call smscore_unregister_client from remove handler
257 while (!list_empty(&coredev->clients))
258 {
259 client = (smscore_client_t *) coredev->clients.next;
260 client->onremove_handler(client->context);
261 }
262}
263
264int smscore_notify_callbacks(smscore_device_t *coredev, struct device *device, int arrival)
265{
266 struct list_head *next, *first;
267 int rc = 0;
268
269 // note: must be called under g_deviceslock
270
271 first = &g_smscore_notifyees;
272
273 for (next = first->next; next != first; next = next->next)
274 {
275 rc = ((smscore_device_notifyee_t *) next)->hotplug(coredev, device, arrival);
276 if (rc < 0)
277 break;
278 }
279
280 return rc;
281}
282
283smscore_buffer_t *smscore_createbuffer(u8* buffer, void* common_buffer, dma_addr_t common_buffer_phys)
284{
285 smscore_buffer_t *cb = kmalloc(sizeof(smscore_buffer_t), GFP_KERNEL);
286 if (!cb)
287 {
288 printk(KERN_INFO "%s kmalloc(...) failed\n", __FUNCTION__);
289 return NULL;
290 }
291
292 cb->p = buffer;
293 cb->offset_in_common = buffer - (u8*) common_buffer;
294 cb->phys = common_buffer_phys + cb->offset_in_common;
295
296 return cb;
297}
298
299/**
300 * creates coredev object for a device, prepares buffers, creates buffer mappings, notifies
301 * registered hotplugs about new device.
302 *
303 * @param params device pointer to struct with device specific parameters and handlers
304 * @param coredev pointer to a value that receives created coredev object
305 *
306 * @return 0 on success, <0 on error.
307 */
308int smscore_register_device(smsdevice_params_t *params, smscore_device_t **coredev)
309{
310 smscore_device_t* dev;
311 u8 *buffer;
312
313 dev = kzalloc(sizeof(smscore_device_t), GFP_KERNEL);
314 if (!dev)
315 {
316 printk(KERN_INFO "%s kzalloc(...) failed\n", __FUNCTION__);
317 return -ENOMEM;
318 }
319
320 // init list entry so it could be safe in smscore_unregister_device
321 INIT_LIST_HEAD(&dev->entry);
322
323 // init queues
324 INIT_LIST_HEAD(&dev->clients);
325 INIT_LIST_HEAD(&dev->subclients);
326 INIT_LIST_HEAD(&dev->buffers);
327
328 // init locks
329 spin_lock_init(&dev->clientslock);
330 spin_lock_init(&dev->bufferslock);
331
332 // init completion events
333 init_completion(&dev->version_ex_done);
334 init_completion(&dev->data_download_done);
335 init_completion(&dev->trigger_done);
336 init_completion(&dev->init_device_done);
337 init_completion(&dev->reload_start_done);
338 init_completion(&dev->resume_done);
339
340 // alloc common buffer
341 dev->common_buffer_size = params->buffer_size * params->num_buffers;
342 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size, &dev->common_buffer_phys, GFP_KERNEL | GFP_DMA);
343 if (!dev->common_buffer)
344 {
345 smscore_unregister_device(dev);
346 return -ENOMEM;
347 }
348
349 // prepare dma buffers
350 for (buffer = dev->common_buffer; dev->num_buffers < params->num_buffers; dev->num_buffers ++, buffer += params->buffer_size)
351 {
352 smscore_buffer_t *cb = smscore_createbuffer(buffer, dev->common_buffer, dev->common_buffer_phys);
353 if (!cb)
354 {
355 smscore_unregister_device(dev);
356 return -ENOMEM;
357 }
358
359 smscore_putbuffer(dev, cb);
360 }
361
362 printk(KERN_INFO "%s allocated %d buffers\n", __FUNCTION__, dev->num_buffers);
363
364 dev->mode = DEVICE_MODE_NONE;
365 dev->context = params->context;
366 dev->device = params->device;
367 dev->setmode_handler = params->setmode_handler;
368 dev->detectmode_handler = params->detectmode_handler;
369 dev->sendrequest_handler = params->sendrequest_handler;
370 dev->preload_handler = params->preload_handler;
371 dev->postload_handler = params->postload_handler;
372
373 dev->device_flags = params->flags;
374 strcpy(dev->devpath, params->devpath);
375
376 // add device to devices list
377 kmutex_lock(&g_smscore_deviceslock);
378 list_add(&dev->entry, &g_smscore_devices);
379 kmutex_unlock(&g_smscore_deviceslock);
380
381 *coredev = dev;
382
383 printk(KERN_INFO "%s device %p created\n", __FUNCTION__, dev);
384
385 return 0;
386}
387
388/**
389 * sets initial device mode and notifies client hotplugs that device is ready
390 *
391 * @param coredev pointer to a coredev object returned by smscore_register_device
392 *
393 * @return 0 on success, <0 on error.
394 */
395int smscore_start_device(smscore_device_t *coredev)
396{
397 int rc = smscore_set_device_mode(coredev, smscore_registry_getmode(coredev->devpath));
398 if (rc < 0)
399 return rc;
400
401 kmutex_lock(&g_smscore_deviceslock);
402
403 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
404
405 printk(KERN_INFO "%s device %p started, rc %d\n", __FUNCTION__, coredev, rc);
406
407 kmutex_unlock(&g_smscore_deviceslock);
408
409 return rc;
410}
411
412int smscore_sendrequest_and_wait(smscore_device_t *coredev, void* buffer, size_t size, struct completion *completion)
413{
414 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
415 if (rc < 0)
416 return rc;
417
418 return wait_for_completion_timeout(completion, msecs_to_jiffies(1000)) ? 0 : -ETIME;
419}
420
421int smscore_load_firmware_family2(smscore_device_t *coredev, void *buffer, size_t size)
422{
423 SmsFirmware_ST* firmware = (SmsFirmware_ST*) buffer;
424 SmsMsgHdr_ST *msg;
425 UINT32 mem_address = firmware->StartAddress;
426 u8* payload = firmware->Payload;
427 int rc = 0;
428
429 if (coredev->preload_handler)
430 {
431 rc = coredev->preload_handler(coredev->context);
432 if (rc < 0)
433 return rc;
434 }
435
436 // PAGE_SIZE buffer shall be enough and dma aligned
437 msg = (SmsMsgHdr_ST *) kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
438 if (!msg)
439 return -ENOMEM;
440
441 if (coredev->mode != DEVICE_MODE_NONE)
442 {
443 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, sizeof(SmsMsgHdr_ST));
444 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, &coredev->reload_start_done);
445 mem_address = *(UINT32*) &payload[20];
446 }
447
448 while (size && rc >= 0)
449 {
450 SmsDataDownload_ST *DataMsg = (SmsDataDownload_ST *) msg;
451 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
452
453 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, (UINT16)(sizeof(SmsMsgHdr_ST) + sizeof(UINT32) + payload_size));
454
455 DataMsg->MemAddr = mem_address;
456 memcpy(DataMsg->Payload, payload, payload_size);
457
458 if (coredev->device_flags & SMS_ROM_NO_RESPONSE && coredev->mode == DEVICE_MODE_NONE)
459 rc = coredev->sendrequest_handler(coredev->context, DataMsg, DataMsg->xMsgHeader.msgLength);
460 else
461 rc = smscore_sendrequest_and_wait(coredev, DataMsg, DataMsg->xMsgHeader.msgLength, &coredev->data_download_done);
462
463 payload += payload_size;
464 size -= payload_size;
465 mem_address += payload_size;
466 }
467
468 if (rc >= 0)
469 {
470 if (coredev->mode == DEVICE_MODE_NONE)
471 {
472 SmsMsgData_ST* TriggerMsg = (SmsMsgData_ST*) msg;
473
474 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, sizeof(SmsMsgHdr_ST) + sizeof(UINT32) * 5);
475
476 TriggerMsg->msgData[0] = firmware->StartAddress; // Entry point
477 TriggerMsg->msgData[1] = 5; // Priority
478 TriggerMsg->msgData[2] = 0x200; // Stack size
479 TriggerMsg->msgData[3] = 0; // Parameter
480 TriggerMsg->msgData[4] = 4; // Task ID
481
482 if (coredev->device_flags & SMS_ROM_NO_RESPONSE)
483 {
484 rc = coredev->sendrequest_handler(coredev->context, TriggerMsg, TriggerMsg->xMsgHeader.msgLength);
485 msleep(100);
486 }
487 else
488 rc = smscore_sendrequest_and_wait(coredev, TriggerMsg, TriggerMsg->xMsgHeader.msgLength, &coredev->trigger_done);
489 }
490 else
491 {
492 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, sizeof(SmsMsgHdr_ST));
493
494 rc = coredev->sendrequest_handler(coredev->context, msg, msg->msgLength);
495 }
496 }
497
498 printk("%s %d \n", __func__, rc);
499
500 kfree(msg);
501
502 return (rc >= 0 && coredev->postload_handler) ?
503 coredev->postload_handler(coredev->context) :
504 rc;
505}
506
507/**
508 * loads specified firmware into a buffer and calls device loadfirmware_handler
509 *
510 * @param coredev pointer to a coredev object returned by smscore_register_device
511 * @param filename null-terminated string specifies firmware file name
512 * @param loadfirmware_handler device handler that loads firmware
513 *
514 * @return 0 on success, <0 on error.
515 */
516int smscore_load_firmware(smscore_device_t *coredev, char* filename, loadfirmware_t loadfirmware_handler)
517{
518 int rc = -ENOENT;
519
520 const struct firmware *fw;
521 u8* fw_buffer;
522
523 if (loadfirmware_handler == NULL && !(coredev->device_flags & SMS_DEVICE_FAMILY2))
524 return -EINVAL;
525
526 rc = request_firmware(&fw, filename, coredev->device);
527 if (rc < 0)
528 {
529 printk(KERN_INFO "%s failed to open \"%s\"\n", __FUNCTION__, filename);
530 return rc;
531 }
532
533 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), GFP_KERNEL | GFP_DMA);
534 if (fw_buffer)
535 {
536 memcpy(fw_buffer, fw->data, fw->size);
537
538 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
539 smscore_load_firmware_family2(coredev, fw_buffer, fw->size) :
540 loadfirmware_handler(coredev->context, fw_buffer, fw->size);
541
542 kfree(fw_buffer);
543 }
544 else
545 {
546 printk(KERN_INFO "%s failed to allocate firmware buffer\n", __FUNCTION__);
547 rc = -ENOMEM;
548 }
549
550 release_firmware(fw);
551
552 return rc;
553}
554
555/**
556 * notifies all clients registered with the device, notifies hotplugs, frees all buffers and coredev object
557 *
558 * @param coredev pointer to a coredev object returned by smscore_register_device
559 *
560 * @return 0 on success, <0 on error.
561 */
562void smscore_unregister_device(smscore_device_t *coredev)
563{
564 smscore_buffer_t *cb;
565 int num_buffers = 0;
566
567 kmutex_lock(&g_smscore_deviceslock);
568
569 smscore_notify_clients(coredev);
570 smscore_notify_callbacks(coredev, NULL, 0);
571
572 // at this point all buffers should be back
573 // onresponse must no longer be called
574
575 while (1)
576 {
577 while ((cb = smscore_getbuffer(coredev)))
578 {
579 kfree(cb);
580 num_buffers ++;
581 }
582
583 if (num_buffers == coredev->num_buffers)
584 break;
585
586 printk(KERN_INFO "%s waiting for %d buffer(s)\n", __FUNCTION__, coredev->num_buffers - num_buffers);
587 msleep(100);
588 }
589
590 printk(KERN_INFO "%s freed %d buffers\n", __FUNCTION__, num_buffers);
591
592 if (coredev->common_buffer)
593 dma_free_coherent(NULL, coredev->common_buffer_size, coredev->common_buffer, coredev->common_buffer_phys);
594
595 list_del(&coredev->entry);
596 kfree(coredev);
597
598 kmutex_unlock(&g_smscore_deviceslock);
599
600 printk(KERN_INFO "%s device %p destroyed\n", __FUNCTION__, coredev);
601}
602
603int smscore_detect_mode(smscore_device_t *coredev)
604{
605 void *buffer = kmalloc(sizeof(SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
606 SmsMsgHdr_ST *msg = (SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
607 int rc;
608
609 if (!buffer)
610 return -ENOMEM;
611
612 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, sizeof(SmsMsgHdr_ST));
613
614 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, &coredev->version_ex_done);
615 if (rc == -ETIME)
616 {
617 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed first try\n", __FUNCTION__);
618
619 if (wait_for_completion_timeout(&coredev->resume_done, msecs_to_jiffies(5000)))
620 {
621 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, &coredev->version_ex_done);
622 if (rc < 0)
623 {
624 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n", __FUNCTION__, rc);
625 }
626 }
627 else
628 rc = -ETIME;
629 }
630
631 kfree(buffer);
632
633 return rc;
634}
635
636char *smscore_fw_lkup[] =
637{
638 "dvb_nova_12mhz.inp",
639 "dvb_nova_12mhz.inp",
640 "tdmb_nova.inp",
641 "none",
642 "dvb_nova_12mhz.inp",
643 "isdbt_nova_12mhz.inp",
644 "isdbt_nova_12mhz.inp",
645 "cmmb_nova_12mhz.inp",
646 "none",
647};
648
649/**
650 * calls device handler to change mode of operation
651 * NOTE: stellar/usb may disconnect when changing mode
652 *
653 * @param coredev pointer to a coredev object returned by smscore_register_device
654 * @param mode requested mode of operation
655 *
656 * @return 0 on success, <0 on error.
657 */
658int smscore_set_device_mode(smscore_device_t *coredev, int mode)
659{
660 void *buffer;
661 int rc = 0;
662
663 if (coredev->device_flags & SMS_DEVICE_FAMILY2)
664 {
665 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER)
666 {
667 printk(KERN_INFO "%s invalid mode specified %d\n", __FUNCTION__, mode);
668 return -EINVAL;
669 }
670
671 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY))
672 {
673 rc = smscore_detect_mode(coredev);
674 if (rc < 0)
675 return rc;
676 }
677
678 if (coredev->mode == mode)
679 {
680 printk(KERN_INFO "%s device mode %d already set\n", __FUNCTION__, mode);
681 return 0;
682 }
683
684 if (!(coredev->modes_supported & (1 << mode)))
685 {
686 rc = smscore_load_firmware(coredev, smscore_fw_lkup[mode], NULL);
687 if (rc < 0)
688 return rc;
689 }
690 else
691 {
692 printk(KERN_INFO "%s mode %d supported by running firmware\n", __FUNCTION__, mode);
693 }
694
695 buffer = kmalloc(sizeof(SmsMsgData_ST) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
696 if (buffer)
697 {
698 SmsMsgData_ST *msg = (SmsMsgData_ST *) SMS_ALIGN_ADDRESS(buffer);
699
700 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, sizeof(SmsMsgData_ST));
701 msg->msgData[0] = mode;
702
703 rc = smscore_sendrequest_and_wait(coredev, msg, msg->xMsgHeader.msgLength, &coredev->init_device_done);
704
705 kfree(buffer);
706 }
707 else
708 rc = -ENOMEM;
709 }
710 else
711 {
712 if (coredev->detectmode_handler)
713 coredev->detectmode_handler(coredev->context, &coredev->mode);
714
715 if (coredev->mode != mode && coredev->setmode_handler)
716 rc = coredev->setmode_handler(coredev->context, mode);
717 }
718
719 smscore_registry_setmode(coredev->devpath, mode);
720
721 if (rc >= 0)
722 {
723 coredev->mode = mode;
724 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
725 }
726
727 return rc;
728}
729
730/**
731 * calls device handler to get current mode of operation
732 *
733 * @param coredev pointer to a coredev object returned by smscore_register_device
734 *
735 * @return current mode
736 */
737int smscore_get_device_mode(smscore_device_t *coredev)
738{
739 return coredev->mode;
740}
741
742smscore_client_t* smscore_getclient_by_type(smscore_device_t *coredev, int data_type)
743{
744 smscore_client_t *client = NULL;
745 struct list_head *next, *first;
746 unsigned long flags;
747
748 if (!data_type)
749 return NULL;
750
751 spin_lock_irqsave(&coredev->clientslock, flags);
752
753 first = &coredev->clients;
754
755 for (next = first->next; next != first; next = next->next)
756 {
757 if (((smscore_client_t*) next)->data_type == data_type)
758 {
759 client = (smscore_client_t*) next;
760 break;
761 }
762 }
763
764 spin_unlock_irqrestore(&coredev->clientslock, flags);
765
766 return client;
767}
768
769smscore_client_t* smscore_getclient_by_id(smscore_device_t *coredev, int id)
770{
771 smscore_client_t *client = NULL;
772 struct list_head *next, *first;
773 unsigned long flags;
774
775 spin_lock_irqsave(&coredev->clientslock, flags);
776
777 first = &coredev->subclients;
778
779 for (next = first->next; next != first; next = next->next)
780 {
781 if (((smscore_subclient_t*) next)->id == id)
782 {
783 client = ((smscore_subclient_t*) next)->client;
784 break;
785 }
786 }
787
788 spin_unlock_irqrestore(&coredev->clientslock, flags);
789
790 return client;
791}
792
793/**
794 * find client by response id/type, call clients onresponse handler
795 * return buffer to pool on error
796 *
797 * @param coredev pointer to a coredev object returned by smscore_register_device
798 * @param cb pointer to response buffer descriptor
799 *
800 */
801void smscore_onresponse(smscore_device_t *coredev, smscore_buffer_t *cb)
802{
803 SmsMsgHdr_ST *phdr = (SmsMsgHdr_ST *)((u8*) cb->p + cb->offset);
804 smscore_client_t * client = smscore_getclient_by_type(coredev, phdr->msgType);
805 int rc = -EBUSY;
806
807 static unsigned long last_sample_time = 0;
808 static int data_total = 0;
809 unsigned long time_now = jiffies_to_msecs(jiffies);
810
811 if (!last_sample_time)
812 last_sample_time = time_now;
813
814 if (time_now - last_sample_time > 10000)
815 {
816 printk("\n%s data rate %d bytes/secs\n", __func__, (int)((data_total * 1000) / (time_now - last_sample_time)));
817
818 last_sample_time = time_now;
819 data_total = 0;
820 }
821
822 data_total += cb->size;
823
824 if (!client)
825 client = smscore_getclient_by_id(coredev, phdr->msgDstId);
826
827 if (client)
828 rc = client->onresponse_handler(client->context, cb);
829
830 if (rc < 0)
831 {
832 switch (phdr->msgType)
833 {
834 case MSG_SMS_GET_VERSION_EX_RES:
835 {
836 SmsVersionRes_ST *ver = (SmsVersionRes_ST*) phdr;
837 printk("%s: MSG_SMS_GET_VERSION_EX_RES id %d prots 0x%x ver %d.%d\n", __FUNCTION__, ver->FirmwareId, ver->SupportedProtocols, ver->RomVersionMajor, ver->RomVersionMinor);
838
839 coredev->mode = ver->FirmwareId == 255 ? DEVICE_MODE_NONE : ver->FirmwareId;
840 coredev->modes_supported = ver->SupportedProtocols;
841
842 complete(&coredev->version_ex_done);
843 break;
844 }
845
846 case MSG_SMS_INIT_DEVICE_RES:
847 printk("%s: MSG_SMS_INIT_DEVICE_RES\n", __FUNCTION__);
848 complete(&coredev->init_device_done);
849 break;
850
851 case MSG_SW_RELOAD_START_RES:
852 printk("%s: MSG_SW_RELOAD_START_RES\n", __FUNCTION__);
853 complete(&coredev->reload_start_done);
854 break;
855
856 case MSG_SMS_DATA_DOWNLOAD_RES:
857 complete(&coredev->data_download_done);
858 break;
859
860 case MSG_SW_RELOAD_EXEC_RES:
861 printk("%s: MSG_SW_RELOAD_EXEC_RES\n", __FUNCTION__);
862 break;
863
864 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
865 printk("%s: MSG_SMS_SWDOWNLOAD_TRIGGER_RES\n", __FUNCTION__);
866 complete(&coredev->trigger_done);
867 break;
868
869 case MSG_SMS_SLEEP_RESUME_COMP_IND:
870 complete(&coredev->resume_done);
871 break;
872
873 default:
874 printk(KERN_INFO "%s no client (%p) or error (%d), type:%d dstid:%d\n", __FUNCTION__, client, rc, phdr->msgType, phdr->msgDstId);
875 }
876
877 smscore_putbuffer(coredev, cb);
878 }
879}
880
881/**
882 * return pointer to next free buffer descriptor from core pool
883 *
884 * @param coredev pointer to a coredev object returned by smscore_register_device
885 *
886 * @return pointer to descriptor on success, NULL on error.
887 */
888smscore_buffer_t *smscore_getbuffer(smscore_device_t *coredev)
889{
890 smscore_buffer_t *cb = NULL;
891 unsigned long flags;
892
893 spin_lock_irqsave(&coredev->bufferslock, flags);
894
895 if (!list_empty(&coredev->buffers))
896 {
897 cb = (smscore_buffer_t *) coredev->buffers.next;
898 list_del(&cb->entry);
899 }
900
901 spin_unlock_irqrestore(&coredev->bufferslock, flags);
902
903 return cb;
904}
905
906/**
907 * return buffer descriptor to a pool
908 *
909 * @param coredev pointer to a coredev object returned by smscore_register_device
910 * @param cb pointer buffer descriptor
911 *
912 */
913void smscore_putbuffer(smscore_device_t *coredev, smscore_buffer_t *cb)
914{
915 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
916}
917
918int smscore_validate_client(smscore_device_t *coredev, smscore_client_t *client, int id)
919{
920 smscore_client_t *existing_client;
921 smscore_subclient_t *subclient;
922
923 if (!id)
924 return 0;
925
926 existing_client = smscore_getclient_by_id(coredev, id);
927 if (existing_client == client)
928 return 0;
929
930 if (existing_client)
931 return -EBUSY;
932
933 subclient = kzalloc(sizeof(smscore_subclient_t), GFP_KERNEL);
934 if (!subclient)
935 return -ENOMEM;
936
937 subclient->client = client;
938 subclient->id = id;
939
940 list_add_locked(&subclient->entry, &coredev->subclients, &coredev->clientslock);
941
942 return 0;
943}
944
945/**
946 * creates smsclient object, check that id is taken by another client
947 *
948 * @param coredev pointer to a coredev object from clients hotplug
949 * @param initial_id all messages with this id would be sent to this client
950 * @param data_type all messages of this type would be sent to this client
951 * @param onresponse_handler client handler that is called to process incoming messages
952 * @param onremove_handler client handler that is called when device is removed
953 * @param context client-specific context
954 * @param client pointer to a value that receives created smsclient object
955 *
956 * @return 0 on success, <0 on error.
957 */
958int smscore_register_client(smscore_device_t *coredev, smsclient_params_t *params, smscore_client_t **client)
959{
960 smscore_client_t* newclient;
961 int rc;
962
963 // check that no other channel with same data type exists
964 if (params->data_type && smscore_getclient_by_type(coredev, params->data_type))
965 return -EEXIST;
966
967 newclient = kzalloc(sizeof(smscore_client_t), GFP_KERNEL);
968 if (!newclient)
969 return -ENOMEM;
970
971 // check that no other channel with same id exists
972 rc = smscore_validate_client(coredev, newclient, params->initial_id);
973 if (rc < 0)
974 {
975 kfree(newclient);
976 return rc;
977 }
978
979 newclient->coredev = coredev;
980 newclient->data_type = params->data_type;
981 newclient->onresponse_handler = params->onresponse_handler;
982 newclient->onremove_handler = params->onremove_handler;
983 newclient->context = params->context;
984
985 list_add_locked(&newclient->entry, &coredev->clients, &coredev->clientslock);
986
987 *client = newclient;
988
989 printk(KERN_INFO "%s %p %d %d\n", __FUNCTION__, params->context, params->data_type, params->initial_id);
990
991 return 0;
992}
993
994/**
995 * frees smsclient object and all subclients associated with it
996 *
997 * @param client pointer to smsclient object returned by smscore_register_client
998 *
999 */
1000void smscore_unregister_client(smscore_client_t *client)
1001{
1002 smscore_device_t *coredev = client->coredev;
1003 struct list_head *next, *first;
1004 unsigned long flags;
1005
1006 spin_lock_irqsave(&coredev->clientslock, flags);
1007
1008 first = &coredev->subclients;
1009
1010 for (next = first->next; next != first;)
1011 {
1012 smscore_subclient_t *subclient = (smscore_subclient_t *) next;
1013 next = next->next;
1014
1015 if (subclient->client == client)
1016 {
1017 list_del(&subclient->entry);
1018 kfree(subclient);
1019 }
1020 }
1021
1022 printk(KERN_INFO "%s %p %d\n", __FUNCTION__, client->context, client->data_type);
1023
1024 list_del(&client->entry);
1025 kfree(client);
1026
1027 spin_unlock_irqrestore(&coredev->clientslock, flags);
1028}
1029
1030/**
1031 * verifies that source id is not taken by another client,
1032 * calls device handler to send requests to the device
1033 *
1034 * @param client pointer to smsclient object returned by smscore_register_client
1035 * @param buffer pointer to a request buffer
1036 * @param size size (in bytes) of request buffer
1037 *
1038 * @return 0 on success, <0 on error.
1039 */
1040int smsclient_sendrequest(smscore_client_t *client, void *buffer, size_t size)
1041{
1042 smscore_device_t* coredev = client->coredev;
1043 SmsMsgHdr_ST* phdr = (SmsMsgHdr_ST*) buffer;
1044
1045 // check that no other channel with same id exists
1046 int rc = smscore_validate_client(client->coredev, client, phdr->msgSrcId);
1047 if (rc < 0)
1048 return rc;
1049
1050 return coredev->sendrequest_handler(coredev->context, buffer, size);
1051}
1052
1053/**
1054 * return the size of large (common) buffer
1055 *
1056 * @param coredev pointer to a coredev object from clients hotplug
1057 *
1058 * @return size (in bytes) of the buffer
1059 */
1060int smscore_get_common_buffer_size(smscore_device_t *coredev)
1061{
1062 return coredev->common_buffer_size;
1063}
1064
1065/**
1066 * maps common buffer (if supported by platform)
1067 *
1068 * @param coredev pointer to a coredev object from clients hotplug
1069 * @param vma pointer to vma struct from mmap handler
1070 *
1071 * @return 0 on success, <0 on error.
1072 */
1073int smscore_map_common_buffer(smscore_device_t *coredev, struct vm_area_struct * vma)
1074{
1075 unsigned long end = vma->vm_end, start = vma->vm_start, size = PAGE_ALIGN(coredev->common_buffer_size);
1076
1077 if (!(vma->vm_flags & (VM_READ | VM_SHARED)) || (vma->vm_flags & VM_WRITE))
1078 {
1079 printk(KERN_INFO "%s invalid vm flags\n", __FUNCTION__);
1080 return -EINVAL;
1081 }
1082
1083 if ((end - start) != size)
1084 {
1085 printk(KERN_INFO "%s invalid size %d expected %d\n", __FUNCTION__, (int)(end - start), (int) size);
1086 return -EINVAL;
1087 }
1088
1089 if (remap_pfn_range(vma, start, coredev->common_buffer_phys >> PAGE_SHIFT, size, pgprot_noncached(vma->vm_page_prot)))
1090 {
1091 printk(KERN_INFO "%s remap_page_range failed\n", __FUNCTION__);
1092 return -EAGAIN;
1093 }
1094
1095 return 0;
1096}
1097
1098int smscore_module_init(void)
1099{
1100 int rc = 0;
1101
1102 INIT_LIST_HEAD(&g_smscore_notifyees);
1103 INIT_LIST_HEAD(&g_smscore_devices);
1104 kmutex_init(&g_smscore_deviceslock);
1105
1106 INIT_LIST_HEAD(&g_smscore_registry);
1107 kmutex_init(&g_smscore_registrylock);
1108
1109 /* USB Register */
1110 rc = smsusb_register();
1111
1112 /* DVB Register */
1113 rc = smsdvb_register();
1114
1115 printk(KERN_INFO "%s, rc %d\n", __FUNCTION__, rc);
1116
1117 return rc;
1118}
1119
1120void smscore_module_exit(void)
1121{
1122
1123 kmutex_lock(&g_smscore_deviceslock);
1124 while (!list_empty(&g_smscore_notifyees))
1125 {
1126 smscore_device_notifyee_t *notifyee = (smscore_device_notifyee_t *) g_smscore_notifyees.next;
1127
1128 list_del(&notifyee->entry);
1129 kfree(notifyee);
1130 }
1131 kmutex_unlock(&g_smscore_deviceslock);
1132
1133 kmutex_lock(&g_smscore_registrylock);
1134 while (!list_empty(&g_smscore_registry))
1135 {
1136 smscore_registry_entry_t *entry = (smscore_registry_entry_t *) g_smscore_registry.next;
1137
1138 list_del(&entry->entry);
1139 kfree(entry);
1140 }
1141 kmutex_unlock(&g_smscore_registrylock);
1142
1143 /* DVB UnRegister */
1144 smsdvb_unregister();
1145
1146 /* Unregister USB */
1147 smsusb_unregister();
1148
1149 printk(KERN_INFO "%s\n", __FUNCTION__);
1150}
1151
1152module_init(smscore_module_init);
1153module_exit(smscore_module_exit);
1154
1155MODULE_DESCRIPTION("smscore");
1156MODULE_AUTHOR("Anatoly Greenblatt,,, (anatolyg@siano-ms.com)");
1157MODULE_LICENSE("GPL");
1158
diff --git a/drivers/media/dvb/siano/smscoreapi.h b/drivers/media/dvb/siano/smscoreapi.h
new file mode 100644
index 000000000000..679487df8a53
--- /dev/null
+++ b/drivers/media/dvb/siano/smscoreapi.h
@@ -0,0 +1,531 @@
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 <asm/scatterlist.h>
30#include <asm/page.h>
31
32#include "dmxdev.h"
33#include "dvbdev.h"
34#include "dvb_demux.h"
35#include "dvb_frontend.h"
36
37#include <linux/mutex.h>
38
39typedef struct mutex kmutex_t;
40
41#define kmutex_init(_p_) mutex_init(_p_)
42#define kmutex_lock(_p_) mutex_lock(_p_)
43#define kmutex_trylock(_p_) mutex_trylock(_p_)
44#define kmutex_unlock(_p_) mutex_unlock(_p_)
45
46
47#ifndef min
48#define min(a,b) (((a) < (b)) ? (a) : (b))
49#endif
50
51#define SMS_ALLOC_ALIGNMENT 128
52#define SMS_DMA_ALIGNMENT 16
53#define SMS_ALIGN_ADDRESS(addr) ((((u32)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
54
55#define SMS_DEVICE_FAMILY2 1
56#define SMS_ROM_NO_RESPONSE 2
57#define SMS_DEVICE_NOT_READY 0x8000000
58
59typedef struct _smscore_device smscore_device_t;
60typedef struct _smscore_client smscore_client_t;
61typedef struct _smscore_buffer smscore_buffer_t;
62
63typedef int (*hotplug_t)(smscore_device_t *coredev, struct device *device, int arrival);
64
65typedef int (*setmode_t)(void *context, int mode);
66typedef void (*detectmode_t)(void *context, int *mode);
67typedef int (*sendrequest_t)(void *context, void *buffer, size_t size);
68typedef int (*loadfirmware_t)(void *context, void *buffer, size_t size);
69typedef int (*preload_t)(void *context);
70typedef int (*postload_t)(void *context);
71
72typedef int (*onresponse_t)(void *context, smscore_buffer_t *cb);
73typedef void (*onremove_t)(void *context);
74
75typedef struct _smscore_buffer
76{
77 // public members, once passed to clients can be changed freely
78 struct list_head entry;
79 int size;
80 int offset;
81
82 // private members, read-only for clients
83 void *p;
84 dma_addr_t phys;
85 unsigned long offset_in_common;
86} *psmscore_buffer_t;
87
88typedef struct _smsdevice_params
89{
90 struct device *device;
91
92 int buffer_size;
93 int num_buffers;
94
95 char devpath[32];
96 unsigned long flags;
97
98 setmode_t setmode_handler;
99 detectmode_t detectmode_handler;
100 sendrequest_t sendrequest_handler;
101 preload_t preload_handler;
102 postload_t postload_handler;
103
104 void *context;
105} smsdevice_params_t;
106
107typedef struct _smsclient_params
108{
109 int initial_id;
110 int data_type;
111 onresponse_t onresponse_handler;
112 onremove_t onremove_handler;
113
114 void *context;
115} smsclient_params_t;
116
117// GPIO definitions for antenna frequency domain control (SMS8021)
118#define SMS_ANTENNA_GPIO_0 1
119#define SMS_ANTENNA_GPIO_1 0
120
121#define BW_8_MHZ 0
122#define BW_7_MHZ 1
123#define BW_6_MHZ 2
124#define BW_5_MHZ 3
125#define BW_ISDBT_1SEG 4
126#define BW_ISDBT_3SEG 5
127
128#define MSG_HDR_FLAG_SPLIT_MSG 4
129
130#define MAX_GPIO_PIN_NUMBER 31
131
132#define HIF_TASK 11
133#define SMS_HOST_LIB 150
134#define DVBT_BDA_CONTROL_MSG_ID 201
135
136#define SMS_MAX_PAYLOAD_SIZE 240
137#define SMS_TUNE_TIMEOUT 500
138
139#define MSG_SMS_GPIO_CONFIG_REQ 507
140#define MSG_SMS_GPIO_CONFIG_RES 508
141#define MSG_SMS_GPIO_SET_LEVEL_REQ 509
142#define MSG_SMS_GPIO_SET_LEVEL_RES 510
143#define MSG_SMS_GPIO_GET_LEVEL_REQ 511
144#define MSG_SMS_GPIO_GET_LEVEL_RES 512
145#define MSG_SMS_RF_TUNE_REQ 561
146#define MSG_SMS_RF_TUNE_RES 562
147#define MSG_SMS_INIT_DEVICE_REQ 578
148#define MSG_SMS_INIT_DEVICE_RES 579
149#define MSG_SMS_ADD_PID_FILTER_REQ 601
150#define MSG_SMS_ADD_PID_FILTER_RES 602
151#define MSG_SMS_REMOVE_PID_FILTER_REQ 603
152#define MSG_SMS_REMOVE_PID_FILTER_RES 604
153#define MSG_SMS_DAB_CHANNEL 607
154#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608
155#define MSG_SMS_GET_PID_FILTER_LIST_RES 609
156#define MSG_SMS_GET_STATISTICS_REQ 615
157#define MSG_SMS_GET_STATISTICS_RES 616
158#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651
159#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652
160#define MSG_SMS_GET_STATISTICS_EX_REQ 653
161#define MSG_SMS_GET_STATISTICS_EX_RES 654
162#define MSG_SMS_SLEEP_RESUME_COMP_IND 655
163#define MSG_SMS_DATA_DOWNLOAD_REQ 660
164#define MSG_SMS_DATA_DOWNLOAD_RES 661
165#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664
166#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665
167#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666
168#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667
169#define MSG_SMS_GET_VERSION_EX_REQ 668
170#define MSG_SMS_GET_VERSION_EX_RES 669
171#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670
172#define MSG_SMS_I2C_SET_FREQ_REQ 685
173#define MSG_SMS_GENERIC_I2C_REQ 687
174#define MSG_SMS_GENERIC_I2C_RES 688
175#define MSG_SMS_DVBT_BDA_DATA 693
176#define MSG_SW_RELOAD_REQ 697
177#define MSG_SMS_DATA_MSG 699
178#define MSG_SW_RELOAD_START_REQ 702
179#define MSG_SW_RELOAD_START_RES 703
180#define MSG_SW_RELOAD_EXEC_REQ 704
181#define MSG_SW_RELOAD_EXEC_RES 705
182#define MSG_SMS_SPI_INT_LINE_SET_REQ 710
183#define MSG_SMS_ISDBT_TUNE_REQ 776
184#define MSG_SMS_ISDBT_TUNE_RES 777
185
186#define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
187 (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
188 (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
189} while (0)
190#define SMS_INIT_MSG(ptr, type, len) SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
191
192typedef enum
193{
194 DEVICE_MODE_NONE = -1,
195 DEVICE_MODE_DVBT = 0,
196 DEVICE_MODE_DVBH,
197 DEVICE_MODE_DAB_TDMB,
198 DEVICE_MODE_DAB_TDMB_DABIP,
199 DEVICE_MODE_DVBT_BDA,
200 DEVICE_MODE_ISDBT,
201 DEVICE_MODE_ISDBT_BDA,
202 DEVICE_MODE_CMMB,
203 DEVICE_MODE_RAW_TUNER,
204 DEVICE_MODE_MAX,
205} SMS_DEVICE_MODE;
206
207typedef unsigned char UINT8;
208typedef unsigned short UINT16;
209typedef unsigned int UINT32;
210typedef int INT32;
211
212typedef struct SmsMsgHdr_S
213{
214 UINT16 msgType;
215 UINT8 msgSrcId;
216 UINT8 msgDstId;
217 UINT16 msgLength; // Length is of the entire message, including header
218 UINT16 msgFlags;
219} SmsMsgHdr_ST;
220
221typedef struct SmsMsgData_S
222{
223 SmsMsgHdr_ST xMsgHeader;
224 UINT32 msgData[1];
225} SmsMsgData_ST;
226
227typedef struct SmsDataDownload_S
228{
229 SmsMsgHdr_ST xMsgHeader;
230 UINT32 MemAddr;
231 UINT8 Payload[SMS_MAX_PAYLOAD_SIZE];
232} SmsDataDownload_ST;
233
234typedef struct SmsVersionRes_S
235{
236 SmsMsgHdr_ST xMsgHeader;
237
238 UINT16 ChipModel; // e.g. 0x1102 for SMS-1102 "Nova"
239 UINT8 Step; // 0 - Step A
240 UINT8 MetalFix; // 0 - Metal 0
241
242 UINT8 FirmwareId; // 0xFF � ROM, otherwise the value indicated by SMSHOSTLIB_DEVICE_MODES_E
243 UINT8 SupportedProtocols; // Bitwise OR combination of supported protocols
244
245 UINT8 VersionMajor;
246 UINT8 VersionMinor;
247 UINT8 VersionPatch;
248 UINT8 VersionFieldPatch;
249
250 UINT8 RomVersionMajor;
251 UINT8 RomVersionMinor;
252 UINT8 RomVersionPatch;
253 UINT8 RomVersionFieldPatch;
254
255 UINT8 TextLabel[34];
256} SmsVersionRes_ST;
257
258typedef struct SmsFirmware_S
259{
260 UINT32 CheckSum;
261 UINT32 Length;
262 UINT32 StartAddress;
263 UINT8 Payload[1];
264} SmsFirmware_ST;
265
266typedef struct SMSHOSTLIB_STATISTICS_S
267{
268 UINT32 Reserved; //!< Reserved
269
270 /// Common parameters
271 UINT32 IsRfLocked; //!< 0 - not locked, 1 - locked
272 UINT32 IsDemodLocked; //!< 0 - not locked, 1 - locked
273 UINT32 IsExternalLNAOn; //!< 0 - external LNA off, 1 - external LNA on
274
275 /// Reception quality
276 INT32 SNR; //!< dB
277 UINT32 BER; //!< Post Viterbi BER [1E-5]
278 UINT32 FIB_CRC; //!< CRC errors percentage, valid only for DAB
279 UINT32 TS_PER; //!< Transport stream PER, 0xFFFFFFFF indicate N/A, valid only for DVB-T/H
280 UINT32 MFER; //!< DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H
281 INT32 RSSI; //!< dBm
282 INT32 InBandPwr; //!< In band power in dBM
283 INT32 CarrierOffset; //!< Carrier Offset in bin/1024
284
285 /// Transmission parameters
286 UINT32 Frequency; //!< Frequency in Hz
287 UINT32 Bandwidth; //!< Bandwidth in MHz, valid only for DVB-T/H
288 UINT32 TransmissionMode; //!< Transmission Mode, for DAB modes 1-4, for DVB-T/H FFT mode carriers in Kilos
289 UINT32 ModemState; //!< from SMS_DvbModemState_ET , valid only for DVB-T/H
290 UINT32 GuardInterval; //!< Guard Interval, 1 divided by value , valid only for DVB-T/H
291 UINT32 CodeRate; //!< Code Rate from SMS_DvbModemState_ET, valid only for DVB-T/H
292 UINT32 LPCodeRate; //!< Low Priority Code Rate from SMS_DvbModemState_ET, valid only for DVB-T/H
293 UINT32 Hierarchy; //!< Hierarchy from SMS_Hierarchy_ET, valid only for DVB-T/H
294 UINT32 Constellation; //!< Constellation from SMS_Constellation_ET, valid only for DVB-T/H
295
296 /// Burst parameters, valid only for DVB-H
297 UINT32 BurstSize; //!< Current burst size in bytes, valid only for DVB-H
298 UINT32 BurstDuration; //!< Current burst duration in mSec, valid only for DVB-H
299 UINT32 BurstCycleTime; //!< Current burst cycle time in mSec, valid only for DVB-H
300 UINT32 CalculatedBurstCycleTime;//!< Current burst cycle time in mSec, as calculated by demodulator, valid only for DVB-H
301 UINT32 NumOfRows; //!< Number of rows in MPE table, valid only for DVB-H
302 UINT32 NumOfPaddCols; //!< Number of padding columns in MPE table, valid only for DVB-H
303 UINT32 NumOfPunctCols; //!< Number of puncturing columns in MPE table, valid only for DVB-H
304 UINT32 ErrorTSPackets; //!< Number of erroneous transport-stream packets
305 UINT32 TotalTSPackets; //!< Total number of transport-stream packets
306 UINT32 NumOfValidMpeTlbs; //!< Number of MPE tables which do not include errors after MPE RS decoding
307 UINT32 NumOfInvalidMpeTlbs; //!< Number of MPE tables which include errors after MPE RS decoding
308 UINT32 NumOfCorrectedMpeTlbs; //!< Number of MPE tables which were corrected by MPE RS decoding
309 /// Common params
310 UINT32 BERErrorCount; //!< Number of errornous SYNC bits.
311 UINT32 BERBitCount; //!< Total number of SYNC bits.
312
313 /// Interface information
314 UINT32 SmsToHostTxErrors; //!< Total number of transmission errors.
315
316 /// DAB/T-DMB
317 UINT32 PreBER; //!< DAB/T-DMB only: Pre Viterbi BER [1E-5]
318
319 /// DVB-H TPS parameters
320 UINT32 CellId; //!< TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered
321
322} SMSHOSTLIB_STATISTICS_ST;
323
324typedef struct
325{
326 UINT32 RequestResult;
327
328 SMSHOSTLIB_STATISTICS_ST Stat;
329
330 // Split the calc of the SNR in DAB
331 UINT32 Signal; //!< dB
332 UINT32 Noise; //!< dB
333
334} SmsMsgStatisticsInfo_ST;
335
336typedef struct SMSHOSTLIB_ISDBT_LAYER_STAT_S
337{
338 // Per-layer information
339 UINT32 CodeRate; //!< Code Rate from SMSHOSTLIB_CODE_RATE_ET, 255 means layer does not exist
340 UINT32 Constellation; //!< Constellation from SMSHOSTLIB_CONSTELLATION_ET, 255 means layer does not exist
341 UINT32 BER; //!< Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A
342 UINT32 BERErrorCount; //!< Post Viterbi Error Bits Count
343 UINT32 BERBitCount; //!< Post Viterbi Total Bits Count
344 UINT32 PreBER; //!< Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A
345 UINT32 TS_PER; //!< Transport stream PER [%], 0xFFFFFFFF indicate N/A
346 UINT32 ErrorTSPackets; //!< Number of erroneous transport-stream packets
347 UINT32 TotalTSPackets; //!< Total number of transport-stream packets
348 UINT32 TILdepthI; //!< Time interleaver depth I parameter, 255 means layer does not exist
349 UINT32 NumberOfSegments; //!< Number of segments in layer A, 255 means layer does not exist
350 UINT32 TMCCErrors; //!< TMCC errors
351} SMSHOSTLIB_ISDBT_LAYER_STAT_ST;
352
353typedef struct SMSHOSTLIB_STATISTICS_ISDBT_S
354{
355 UINT32 StatisticsType; //!< Enumerator identifying the type of the structure. Values are the same as SMSHOSTLIB_DEVICE_MODES_E
356 //!< This fiels MUST always first in any statistics structure
357
358 UINT32 FullSize; //!< Total size of the structure returned by the modem. If the size requested by
359 //!< the host is smaller than FullSize, the struct will be truncated
360
361 // Common parameters
362 UINT32 IsRfLocked; //!< 0 - not locked, 1 - locked
363 UINT32 IsDemodLocked; //!< 0 - not locked, 1 - locked
364 UINT32 IsExternalLNAOn; //!< 0 - external LNA off, 1 - external LNA on
365
366 // Reception quality
367 INT32 SNR; //!< dB
368 INT32 RSSI; //!< dBm
369 INT32 InBandPwr; //!< In band power in dBM
370 INT32 CarrierOffset; //!< Carrier Offset in Hz
371
372 // Transmission parameters
373 UINT32 Frequency; //!< Frequency in Hz
374 UINT32 Bandwidth; //!< Bandwidth in MHz
375 UINT32 TransmissionMode; //!< ISDB-T transmission mode
376 UINT32 ModemState; //!< 0 - Acquisition, 1 - Locked
377 UINT32 GuardInterval; //!< Guard Interval, 1 divided by value
378 UINT32 SystemType; //!< ISDB-T system type (ISDB-T / ISDB-Tsb)
379 UINT32 PartialReception; //!< TRUE - partial reception, FALSE otherwise
380 UINT32 NumOfLayers; //!< Number of ISDB-T layers in the network
381
382 // Per-layer information
383 // Layers A, B and C
384 SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; //!< Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST
385
386 // Interface information
387 UINT32 SmsToHostTxErrors; //!< Total number of transmission errors.
388
389} SMSHOSTLIB_STATISTICS_ISDBT_ST;
390
391typedef struct SMSHOSTLIB_STATISTICS_DVB_S
392{
393 UINT32 StatisticsType; //!< Enumerator identifying the type of the structure. Values are the same as SMSHOSTLIB_DEVICE_MODES_E
394 //!< This fiels MUST always first in any statistics structure
395
396 UINT32 FullSize; //!< Total size of the structure returned by the modem. If the size requested by
397 //!< the host is smaller than FullSize, the struct will be truncated
398 // Common parameters
399 UINT32 IsRfLocked; //!< 0 - not locked, 1 - locked
400 UINT32 IsDemodLocked; //!< 0 - not locked, 1 - locked
401 UINT32 IsExternalLNAOn; //!< 0 - external LNA off, 1 - external LNA on
402
403 // Reception quality
404 INT32 SNR; //!< dB
405 UINT32 BER; //!< Post Viterbi BER [1E-5]
406 UINT32 BERErrorCount; //!< Number of errornous SYNC bits.
407 UINT32 BERBitCount; //!< Total number of SYNC bits.
408 UINT32 TS_PER; //!< Transport stream PER, 0xFFFFFFFF indicate N/A
409 UINT32 MFER; //!< DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H
410 INT32 RSSI; //!< dBm
411 INT32 InBandPwr; //!< In band power in dBM
412 INT32 CarrierOffset; //!< Carrier Offset in bin/1024
413
414 // Transmission parameters
415 UINT32 Frequency; //!< Frequency in Hz
416 UINT32 Bandwidth; //!< Bandwidth in MHz
417 UINT32 ModemState; //!< from SMSHOSTLIB_DVB_MODEM_STATE_ET
418 UINT32 TransmissionMode; //!< FFT mode carriers in Kilos
419 UINT32 GuardInterval; //!< Guard Interval, 1 divided by value
420 UINT32 CodeRate; //!< Code Rate from SMSHOSTLIB_CODE_RATE_ET
421 UINT32 LPCodeRate; //!< Low Priority Code Rate from SMSHOSTLIB_CODE_RATE_ET
422 UINT32 Hierarchy; //!< Hierarchy from SMSHOSTLIB_HIERARCHY_ET
423 UINT32 Constellation; //!< Constellation from SMSHOSTLIB_CONSTELLATION_ET
424
425 // Burst parameters, valid only for DVB-H
426 UINT32 BurstSize; //!< Current burst size in bytes, valid only for DVB-H
427 UINT32 BurstDuration; //!< Current burst duration in mSec, valid only for DVB-H
428 UINT32 BurstCycleTime; //!< Current burst cycle time in mSec, valid only for DVB-H
429 UINT32 CalculatedBurstCycleTime;//!< Current burst cycle time in mSec, as calculated by demodulator, valid only for DVB-H
430 UINT32 NumOfRows; //!< Number of rows in MPE table, valid only for DVB-H
431 UINT32 NumOfPaddCols; //!< Number of padding columns in MPE table, valid only for DVB-H
432 UINT32 NumOfPunctCols; //!< Number of puncturing columns in MPE table, valid only for DVB-H
433 UINT32 ErrorTSPackets; //!< Number of erroneous transport-stream packets
434 UINT32 TotalTSPackets; //!< Total number of transport-stream packets
435 UINT32 NumOfValidMpeTlbs; //!< Number of MPE tables which do not include errors after MPE RS decoding, valid only for DVB-H
436 UINT32 NumOfInvalidMpeTlbs; //!< Number of MPE tables which include errors after MPE RS decoding, valid only for DVB-H
437 UINT32 NumOfCorrectedMpeTlbs; //!< Number of MPE tables which were corrected by MPE RS decoding, valid only for DVB-H
438 UINT32 NumMPEReceived; //!< DVB-H, Num MPE section received
439
440 // DVB-H TPS parameters
441 UINT32 CellId; //!< TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered
442 UINT32 DvbhSrvIndHP; //!< DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator
443 UINT32 DvbhSrvIndLP; //!< DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator
444
445 // Interface information
446 UINT32 SmsToHostTxErrors; //!< Total number of transmission errors.
447
448} SMSHOSTLIB_STATISTICS_DVB_ST;
449
450typedef struct SMSHOSTLIB_GPIO_CONFIG_S
451{
452 UINT8 Direction; //!< GPIO direction: Input - 0, Output - 1
453 UINT8 PullUpDown; //!< PullUp/PullDown: None - 0, PullDown - 1, PullUp - 2, Keeper - 3
454 UINT8 InputCharacteristics; //!< Input Characteristics: Normal - 0, Schmitt trigger - 1
455 UINT8 OutputSlewRate; //!< Output Slew Rate: Fast slew rate - 0, Slow slew rate - 1
456 UINT8 OutputDriving; //!< Output driving capability: 4mA - 0, 8mA - 1, 12mA - 2, 16mA - 3
457} SMSHOSTLIB_GPIO_CONFIG_ST;
458
459typedef struct SMSHOSTLIB_I2C_REQ_S
460{
461 UINT32 DeviceAddress; // I2c device address
462 UINT32 WriteCount; // number of bytes to write
463 UINT32 ReadCount; // number of bytes to read
464 UINT8 Data[1];
465} SMSHOSTLIB_I2C_REQ_ST;
466
467typedef struct SMSHOSTLIB_I2C_RES_S
468{
469 UINT32 Status; // non-zero value in case of failure
470 UINT32 ReadCount; // number of bytes read
471 UINT8 Data[1];
472} SMSHOSTLIB_I2C_RES_ST;
473
474typedef struct _smsdvb_client
475{
476 struct list_head entry;
477
478 smscore_device_t *coredev;
479 smscore_client_t *smsclient;
480
481 struct dvb_adapter adapter;
482 struct dvb_demux demux;
483 struct dmxdev dmxdev;
484 struct dvb_frontend frontend;
485
486 fe_status_t fe_status;
487 int fe_ber, fe_snr, fe_signal_strength;
488
489 struct completion tune_done, stat_done;
490
491 // todo: save freq/band instead whole struct
492 struct dvb_frontend_parameters fe_params;
493
494} smsdvb_client_t;
495
496extern void smscore_registry_setmode(char *devpath, int mode);
497extern int smscore_registry_getmode(char *devpath);
498
499extern int smscore_register_hotplug(hotplug_t hotplug);
500extern void smscore_unregister_hotplug(hotplug_t hotplug);
501
502extern int smscore_register_device(smsdevice_params_t *params, smscore_device_t **coredev);
503extern void smscore_unregister_device(smscore_device_t *coredev);
504
505extern int smscore_start_device(smscore_device_t *coredev);
506extern int smscore_load_firmware(smscore_device_t *coredev, char* filename, loadfirmware_t loadfirmware_handler);
507
508extern int smscore_set_device_mode(smscore_device_t *coredev, int mode);
509extern int smscore_get_device_mode(smscore_device_t *coredev);
510
511extern int smscore_register_client(smscore_device_t *coredev, smsclient_params_t* params, smscore_client_t **client);
512extern void smscore_unregister_client(smscore_client_t *client);
513
514extern int smsclient_sendrequest(smscore_client_t *client, void *buffer, size_t size);
515extern void smscore_onresponse(smscore_device_t *coredev, smscore_buffer_t *cb);
516
517extern int smscore_get_common_buffer_size(smscore_device_t *coredev);
518extern int smscore_map_common_buffer(smscore_device_t *coredev, struct vm_area_struct * vma);
519
520extern smscore_buffer_t *smscore_getbuffer(smscore_device_t *coredev);
521extern void smscore_putbuffer(smscore_device_t *coredev, smscore_buffer_t *cb);
522
523/* smsdvb.c */
524int smsdvb_register(void);
525void smsdvb_unregister(void);
526
527/* smsusb.c */
528int smsusb_register(void);
529void smsusb_unregister(void);
530
531#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..e1a14a812c25
--- /dev/null
+++ b/drivers/media/dvb/siano/smsdvb.c
@@ -0,0 +1,425 @@
1/*
2 * Driver for the Siano SMS10xx 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
27DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
28
29struct list_head g_smsdvb_clients;
30kmutex_t g_smsdvb_clientslock;
31
32int smsdvb_onresponse(void *context, smscore_buffer_t *cb)
33{
34 smsdvb_client_t *client = (smsdvb_client_t *) context;
35 SmsMsgHdr_ST *phdr = (SmsMsgHdr_ST *)(((u8*) cb->p) + cb->offset);
36
37 switch(phdr->msgType)
38 {
39 case MSG_SMS_DVBT_BDA_DATA:
40 dvb_dmx_swfilter(&client->demux, (u8*)(phdr + 1), cb->size - sizeof(SmsMsgHdr_ST));
41 break;
42
43 case MSG_SMS_RF_TUNE_RES:
44 complete(&client->tune_done);
45 break;
46
47 case MSG_SMS_GET_STATISTICS_RES:
48 {
49 SmsMsgStatisticsInfo_ST* p = (SmsMsgStatisticsInfo_ST*)(phdr + 1);
50
51 if (p->Stat.IsDemodLocked)
52 {
53 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
54 client->fe_snr = p->Stat.SNR;
55 client->fe_ber = p->Stat.BER;
56
57 if (p->Stat.InBandPwr < -95)
58 client->fe_signal_strength = 0;
59 else if (p->Stat.InBandPwr > -29)
60 client->fe_signal_strength = 100;
61 else
62 client->fe_signal_strength = (p->Stat.InBandPwr + 95) * 3 / 2;
63 }
64 else
65 {
66 client->fe_status = 0;
67 client->fe_snr =
68 client->fe_ber =
69 client->fe_signal_strength = 0;
70 }
71
72 complete(&client->stat_done);
73 break;
74 }
75 }
76
77 smscore_putbuffer(client->coredev, cb);
78
79 return 0;
80}
81
82void smsdvb_unregister_client(smsdvb_client_t* client)
83{
84 // must be called under clientslock
85
86 list_del(&client->entry);
87
88 smscore_unregister_client(client->smsclient);
89 dvb_unregister_frontend(&client->frontend);
90 dvb_dmxdev_release(&client->dmxdev);
91 dvb_dmx_release(&client->demux);
92 dvb_unregister_adapter(&client->adapter);
93 kfree(client);
94}
95
96void smsdvb_onremove(void *context)
97{
98 kmutex_lock(&g_smsdvb_clientslock);
99
100 smsdvb_unregister_client((smsdvb_client_t*) context);
101
102 kmutex_unlock(&g_smsdvb_clientslock);
103}
104
105static int smsdvb_start_feed(struct dvb_demux_feed *feed)
106{
107 smsdvb_client_t *client = container_of(feed->demux, smsdvb_client_t, demux);
108 SmsMsgData_ST PidMsg;
109
110 printk("%s add pid %d(%x)\n", __FUNCTION__, feed->pid, feed->pid);
111
112 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
113 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
114 PidMsg.xMsgHeader.msgFlags = 0;
115 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
116 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
117 PidMsg.msgData[0] = feed->pid;
118
119 return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg));
120}
121
122static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
123{
124 smsdvb_client_t *client = container_of(feed->demux, smsdvb_client_t, demux);
125 SmsMsgData_ST PidMsg;
126
127 printk("%s remove pid %d(%x)\n", __FUNCTION__, feed->pid, feed->pid);
128
129 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
130 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
131 PidMsg.xMsgHeader.msgFlags = 0;
132 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
133 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
134 PidMsg.msgData[0] = feed->pid;
135
136 return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg));
137}
138
139static int smsdvb_sendrequest_and_wait(smsdvb_client_t *client, void* buffer, size_t size, struct completion *completion)
140{
141 int rc = smsclient_sendrequest(client->smsclient, buffer, size);
142 if (rc < 0)
143 return rc;
144
145 return wait_for_completion_timeout(completion, msecs_to_jiffies(2000)) ? 0 : -ETIME;
146}
147
148static int smsdvb_send_statistics_request(smsdvb_client_t *client)
149{
150 SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, DVBT_BDA_CONTROL_MSG_ID, HIF_TASK, sizeof(SmsMsgHdr_ST), 0 };
151 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->stat_done);
152}
153
154static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
155{
156 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
157 int rc = smsdvb_send_statistics_request(client);
158
159 if (!rc)
160 *stat = client->fe_status;
161
162 return rc;
163}
164
165static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
166{
167 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
168 int rc = smsdvb_send_statistics_request(client);
169
170 if (!rc)
171 *ber = client->fe_ber;
172
173 return rc;
174}
175
176static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
177{
178 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
179 int rc = smsdvb_send_statistics_request(client);
180
181 if (!rc)
182 *strength = client->fe_signal_strength;
183
184 return rc;
185}
186
187static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
188{
189 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
190 int rc = smsdvb_send_statistics_request(client);
191
192 if (!rc)
193 *snr = client->fe_snr;
194
195 return rc;
196}
197
198static int smsdvb_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
199{
200 printk("%s\n", __FUNCTION__);
201
202 tune->min_delay_ms = 400;
203 tune->step_size = 250000;
204 tune->max_drift = 0;
205 return 0;
206}
207
208static int smsdvb_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
209{
210 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
211
212 struct
213 {
214 SmsMsgHdr_ST Msg;
215 u32 Data[3];
216 } Msg;
217
218 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
219 Msg.Msg.msgDstId = HIF_TASK;
220 Msg.Msg.msgFlags = 0;
221 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
222 Msg.Msg.msgLength = sizeof(Msg);
223 Msg.Data[0] = fep->frequency;
224 Msg.Data[2] = 12000000;
225
226 printk("%s freq %d band %d\n", __FUNCTION__, fep->frequency, fep->u.ofdm.bandwidth);
227
228 switch(fep->u.ofdm.bandwidth)
229 {
230 case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
231 case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
232 case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
233// case BANDWIDTH_5_MHZ: Msg.Data[1] = BW_5_MHZ; break;
234 case BANDWIDTH_AUTO: return -EOPNOTSUPP;
235 default: return -EINVAL;
236 }
237
238 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->tune_done);
239}
240
241static int smsdvb_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
242{
243 smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
244
245 printk("%s\n", __FUNCTION__);
246
247 // todo:
248 memcpy(fep, &client->fe_params, sizeof(struct dvb_frontend_parameters));
249 return 0;
250}
251
252static void smsdvb_release(struct dvb_frontend *fe)
253{
254 // do nothing
255}
256
257static struct dvb_frontend_ops smsdvb_fe_ops = {
258 .info = {
259 .name = "Siano Mobile Digital SMS10xx",
260 .type = FE_OFDM,
261 .frequency_min = 44250000,
262 .frequency_max = 867250000,
263 .frequency_stepsize = 250000,
264 .caps = FE_CAN_INVERSION_AUTO |
265 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
266 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
267 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
268 FE_CAN_TRANSMISSION_MODE_AUTO |
269 FE_CAN_GUARD_INTERVAL_AUTO |
270 FE_CAN_RECOVER |
271 FE_CAN_HIERARCHY_AUTO,
272 },
273
274 .release = smsdvb_release,
275
276 .set_frontend = smsdvb_set_frontend,
277 .get_frontend = smsdvb_get_frontend,
278 .get_tune_settings = smsdvb_get_tune_settings,
279
280 .read_status = smsdvb_read_status,
281 .read_ber = smsdvb_read_ber,
282 .read_signal_strength = smsdvb_read_signal_strength,
283 .read_snr = smsdvb_read_snr,
284};
285
286int smsdvb_hotplug(smscore_device_t *coredev, struct device* device, int arrival)
287{
288 smsclient_params_t params;
289 smsdvb_client_t* client;
290 int rc;
291
292 // device removal handled by onremove callback
293 if (!arrival)
294 return 0;
295
296 if (smscore_get_device_mode(coredev) != 4)
297 {
298 rc = smscore_set_device_mode(coredev, 4);
299 if (rc < 0)
300 return rc;
301 }
302
303 client = kzalloc(sizeof(smsdvb_client_t), GFP_KERNEL);
304 if (!client)
305 {
306 printk(KERN_INFO "%s kmalloc() failed\n", __FUNCTION__);
307 return -ENOMEM;
308 }
309
310 // register dvb adapter
311 rc = dvb_register_adapter(&client->adapter, "Siano Digital Receiver", THIS_MODULE, device, adapter_nr);
312 if (rc < 0)
313 {
314 printk("%s dvb_register_adapter() failed %d\n", __func__, rc);
315 goto adapter_error;
316 }
317
318 // init dvb demux
319 client->demux.dmx.capabilities = DMX_TS_FILTERING;
320 client->demux.filternum = 32; // todo: nova ???
321 client->demux.feednum = 32;
322 client->demux.start_feed = smsdvb_start_feed;
323 client->demux.stop_feed = smsdvb_stop_feed;
324
325 rc = dvb_dmx_init(&client->demux);
326 if (rc < 0)
327 {
328 printk("%s dvb_dmx_init failed %d\n\n", __FUNCTION__, rc);
329 goto dvbdmx_error;
330 }
331
332 // init dmxdev
333 client->dmxdev.filternum = 32;
334 client->dmxdev.demux = &client->demux.dmx;
335 client->dmxdev.capabilities = 0;
336
337 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
338 if (rc < 0)
339 {
340 printk("%s dvb_dmxdev_init failed %d\n", __FUNCTION__, rc);
341 goto dmxdev_error;
342 }
343
344 // init and register frontend
345 memcpy(&client->frontend.ops, &smsdvb_fe_ops, sizeof(struct dvb_frontend_ops));
346
347 rc = dvb_register_frontend(&client->adapter, &client->frontend);
348 if (rc < 0)
349 {
350 printk("%s frontend registration failed %d\n", __FUNCTION__, rc);
351 goto frontend_error;
352 }
353
354 params.initial_id = 0;
355 params.data_type = MSG_SMS_DVBT_BDA_DATA;
356 params.onresponse_handler = smsdvb_onresponse;
357 params.onremove_handler = smsdvb_onremove;
358 params.context = client;
359
360 rc = smscore_register_client(coredev, &params, &client->smsclient);
361 if (rc < 0)
362 {
363 printk(KERN_INFO "%s smscore_register_client() failed %d\n", __FUNCTION__, rc);
364 goto client_error;
365 }
366
367 client->coredev = coredev;
368
369 init_completion(&client->tune_done);
370 init_completion(&client->stat_done);
371
372 kmutex_lock(&g_smsdvb_clientslock);
373
374 list_add(&client->entry, &g_smsdvb_clients);
375
376 kmutex_unlock(&g_smsdvb_clientslock);
377
378 printk(KERN_INFO "%s success\n", __FUNCTION__);
379
380 return 0;
381
382client_error:
383 dvb_unregister_frontend(&client->frontend);
384
385frontend_error:
386 dvb_dmxdev_release(&client->dmxdev);
387
388dmxdev_error:
389 dvb_dmx_release(&client->demux);
390
391dvbdmx_error:
392 dvb_unregister_adapter(&client->adapter);
393
394adapter_error:
395 kfree(client);
396 return rc;
397}
398
399int smsdvb_register(void)
400{
401 int rc;
402
403 INIT_LIST_HEAD(&g_smsdvb_clients);
404 kmutex_init(&g_smsdvb_clientslock);
405
406 rc = smscore_register_hotplug(smsdvb_hotplug);
407
408 printk(KERN_INFO "%s\n", __FUNCTION__);
409
410 return rc;
411}
412
413void smsdvb_unregister(void)
414{
415 smscore_unregister_hotplug(smsdvb_hotplug);
416
417 kmutex_lock(&g_smsdvb_clientslock);
418
419 while (!list_empty(&g_smsdvb_clients))
420 smsdvb_unregister_client((smsdvb_client_t*) g_smsdvb_clients.next);
421
422 kmutex_unlock(&g_smsdvb_clientslock);
423
424}
425
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
new file mode 100644
index 000000000000..20aa878d9d5f
--- /dev/null
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -0,0 +1,436 @@
1/*
2 * Driver for the Siano SMS10xx 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
29#define USB1_BUFFER_SIZE 0x1000
30#define USB2_BUFFER_SIZE 0x4000
31
32#define MAX_BUFFERS 50
33#define MAX_URBS 10
34
35typedef struct _smsusb_device smsusb_device_t;
36
37typedef struct _smsusb_urb
38{
39 smscore_buffer_t *cb;
40 smsusb_device_t *dev;
41
42 struct urb urb;
43} smsusb_urb_t;
44
45typedef struct _smsusb_device
46{
47 struct usb_device* udev;
48 smscore_device_t *coredev;
49
50 smsusb_urb_t surbs[MAX_URBS];
51
52 int response_alignment;
53 int buffer_size;
54} *psmsusb_device_t;
55
56int smsusb_submit_urb(smsusb_device_t* dev, smsusb_urb_t* surb);
57
58void smsusb_onresponse(struct urb *urb)
59{
60 smsusb_urb_t *surb = (smsusb_urb_t *) urb->context;
61 smsusb_device_t *dev = surb->dev;
62
63 if (urb->status < 0)
64 {
65 printk(KERN_INFO "%s error, urb status %d, %d bytes\n", __FUNCTION__, urb->status, urb->actual_length);
66 return;
67 }
68
69 if (urb->actual_length > 0)
70 {
71 SmsMsgHdr_ST *phdr = (SmsMsgHdr_ST *) surb->cb->p;
72
73 if (urb->actual_length >= phdr->msgLength)
74 {
75 surb->cb->size = phdr->msgLength;
76
77 if (dev->response_alignment && (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG))
78 {
79 surb->cb->offset = dev->response_alignment + ((phdr->msgFlags >> 8) & 3);
80
81 // sanity check
82 if (((int) phdr->msgLength + surb->cb->offset) > urb->actual_length)
83 {
84 printk("%s: invalid response msglen %d offset %d size %d\n", __FUNCTION__, phdr->msgLength, surb->cb->offset, urb->actual_length);
85 goto exit_and_resubmit;
86 }
87
88 // move buffer pointer and copy header to its new location
89 memcpy((char*) phdr + surb->cb->offset, phdr, sizeof(SmsMsgHdr_ST));
90 }
91 else
92 surb->cb->offset = 0;
93
94 smscore_onresponse(dev->coredev, surb->cb);
95 surb->cb = NULL;
96 }
97 else
98 {
99 printk("%s invalid response msglen %d actual %d\n", __FUNCTION__, phdr->msgLength, urb->actual_length);
100 }
101 }
102
103exit_and_resubmit:
104 smsusb_submit_urb(dev, surb);
105}
106
107int smsusb_submit_urb(smsusb_device_t* dev, smsusb_urb_t* surb)
108{
109 if (!surb->cb)
110 {
111 surb->cb = smscore_getbuffer(dev->coredev);
112 if (!surb->cb)
113 {
114 printk(KERN_INFO "%s smscore_getbuffer(...) returned NULL\n", __FUNCTION__);
115 return -ENOMEM;
116 }
117 }
118
119 usb_fill_bulk_urb(
120 &surb->urb,
121 dev->udev,
122 usb_rcvbulkpipe(dev->udev, 0x81),
123 surb->cb->p,
124 dev->buffer_size,
125 smsusb_onresponse,
126 surb
127 );
128 surb->urb.transfer_dma = surb->cb->phys;
129 surb->urb.transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
130
131 return usb_submit_urb(&surb->urb, GFP_ATOMIC);
132}
133
134void smsusb_stop_streaming(smsusb_device_t* dev)
135{
136 int i;
137
138 for (i = 0; i < MAX_URBS; i ++)
139 {
140 usb_kill_urb(&dev->surbs[i].urb);
141
142 if (dev->surbs[i].cb)
143 {
144 smscore_putbuffer(dev->coredev, dev->surbs[i].cb);
145 dev->surbs[i].cb = NULL;
146 }
147 }
148}
149
150int smsusb_start_streaming(smsusb_device_t* dev)
151{
152 int i, rc;
153
154 for (i = 0; i < MAX_URBS; i ++)
155 {
156 rc = smsusb_submit_urb(dev, &dev->surbs[i]);
157 if (rc < 0)
158 {
159 printk(KERN_INFO "%s smsusb_submit_urb(...) failed\n", __FUNCTION__);
160 smsusb_stop_streaming(dev);
161 break;
162 }
163 }
164
165 return rc;
166}
167
168int smsusb_sendrequest(void *context, void *buffer, size_t size)
169{
170 smsusb_device_t* dev = (smsusb_device_t*) context;
171 int dummy;
172
173 return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000);
174}
175
176char *smsusb1_fw_lkup[] =
177{
178 "dvbt_stellar_usb.inp",
179 "dvbh_stellar_usb.inp",
180 "tdmb_stellar_usb.inp",
181 "none",
182 "dvbt_bda_stellar_usb.inp",
183};
184
185int smsusb1_load_firmware(struct usb_device *udev, int id)
186{
187 const struct firmware *fw;
188 u8* fw_buffer;
189 int rc, dummy;
190
191 if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA)
192 {
193 printk(KERN_INFO "%s invalid firmware id specified %d\n", __FUNCTION__, id);
194 return -EINVAL;
195 }
196
197 rc = request_firmware(&fw, smsusb1_fw_lkup[id], &udev->dev);
198 if (rc < 0)
199 {
200 printk(KERN_INFO "%s failed to open \"%s\" mode %d\n", __FUNCTION__, smsusb1_fw_lkup[id], id);
201 return rc;
202 }
203
204 fw_buffer = kmalloc(fw->size, GFP_KERNEL);
205 if (fw_buffer)
206 {
207 memcpy(fw_buffer, fw->data, fw->size);
208
209 rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000);
210
211 printk(KERN_INFO "%s: sent %d(%d) bytes, rc %d\n", __FUNCTION__, fw->size, dummy, rc);
212
213 kfree(fw_buffer);
214 }
215 else
216 {
217 printk(KERN_INFO "failed to allocate firmware buffer\n");
218 rc = -ENOMEM;
219 }
220
221 release_firmware(fw);
222
223 return rc;
224}
225
226void smsusb1_detectmode(void *context, int *mode)
227{
228 char *product_string = ((smsusb_device_t *) context)->udev->product;
229
230 *mode = DEVICE_MODE_NONE;
231
232 if (!product_string)
233 {
234 product_string = "none";
235 printk("%s product string not found\n", __FUNCTION__);
236 }
237 else
238 {
239 if (strstr(product_string, "DVBH"))
240 *mode = 1;
241 else if (strstr(product_string, "BDA"))
242 *mode = 4;
243 else if (strstr(product_string, "DVBT"))
244 *mode = 0;
245 else if (strstr(product_string, "TDMB"))
246 *mode = 2;
247 }
248
249 printk("%s: %d \"%s\"\n", __FUNCTION__, *mode, product_string);
250}
251
252int smsusb1_setmode(void *context, int mode)
253{
254 SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, sizeof(SmsMsgHdr_ST), 0 };
255
256 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA)
257 {
258 printk(KERN_INFO "%s invalid firmware id specified %d\n", __FUNCTION__, mode);
259 return -EINVAL;
260 }
261
262 return smsusb_sendrequest(context, &Msg, sizeof(Msg));
263}
264
265void smsusb_term_device(struct usb_interface *intf)
266{
267 smsusb_device_t *dev = (smsusb_device_t*) usb_get_intfdata(intf);
268
269 if (dev)
270 {
271 smsusb_stop_streaming(dev);
272
273 // unregister from smscore
274 if (dev->coredev)
275 smscore_unregister_device(dev->coredev);
276
277 kfree(dev);
278
279 printk(KERN_INFO "%s device %p destroyed\n", __FUNCTION__, dev);
280 }
281
282 usb_set_intfdata(intf, NULL);
283}
284
285int smsusb_init_device(struct usb_interface *intf)
286{
287 smsdevice_params_t params;
288 smsusb_device_t* dev;
289 int i, rc;
290
291 // create device object
292 dev = kzalloc(sizeof(smsusb_device_t), GFP_KERNEL);
293 if (!dev)
294 {
295 printk(KERN_INFO "%s kzalloc(sizeof(smsusb_device_t) failed\n", __FUNCTION__);
296 return -ENOMEM;
297 }
298
299 memset(&params, 0, sizeof(params));
300 usb_set_intfdata(intf, dev);
301 dev->udev = interface_to_usbdev(intf);
302
303 switch (dev->udev->descriptor.idProduct)
304 {
305 case 0x100:
306 dev->buffer_size = USB1_BUFFER_SIZE;
307
308 params.setmode_handler = smsusb1_setmode;
309 params.detectmode_handler = smsusb1_detectmode;
310 break;
311
312 default:
313 dev->buffer_size = USB2_BUFFER_SIZE;
314 dev->response_alignment = dev->udev->ep_in[1]->desc.wMaxPacketSize - sizeof(SmsMsgHdr_ST);
315
316 params.flags |= SMS_DEVICE_FAMILY2;
317 break;
318 }
319
320 params.device = &dev->udev->dev;
321 params.buffer_size = dev->buffer_size;
322 params.num_buffers = MAX_BUFFERS;
323 params.sendrequest_handler = smsusb_sendrequest;
324 params.context = dev;
325 snprintf(params.devpath, sizeof(params.devpath), "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
326
327 // register in smscore
328 rc = smscore_register_device(&params, &dev->coredev);
329 if (rc < 0)
330 {
331 printk(KERN_INFO "%s smscore_register_device(...) failed, rc %d\n", __FUNCTION__, rc);
332 smsusb_term_device(intf);
333 return rc;
334 }
335
336 // initialize urbs
337 for (i = 0; i < MAX_URBS; i ++)
338 {
339 dev->surbs[i].dev = dev;
340 usb_init_urb(&dev->surbs[i].urb);
341 }
342
343 rc = smsusb_start_streaming(dev);
344 if (rc < 0)
345 {
346 printk(KERN_INFO "%s smsusb_start_streaming(...) failed\n", __FUNCTION__);
347 smsusb_term_device(intf);
348 return rc;
349 }
350
351 rc = smscore_start_device(dev->coredev);
352 if (rc < 0)
353 {
354 printk(KERN_INFO "%s smscore_start_device(...) failed\n", __FUNCTION__);
355 smsusb_term_device(intf);
356 return rc;
357 }
358
359 printk(KERN_INFO "%s device %p created\n", __FUNCTION__, dev);
360
361 return rc;
362}
363
364int smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
365{
366 struct usb_device *udev = interface_to_usbdev(intf);
367 char devpath[32];
368 int i, rc;
369
370 if (intf->num_altsetting > 0)
371 {
372 rc = usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 0);
373 if (rc < 0)
374 {
375 printk(KERN_INFO "%s usb_set_interface failed, rc %d\n", __FUNCTION__, rc);
376 return rc;
377 }
378 }
379
380 printk(KERN_INFO "smsusb_probe %d\n", intf->cur_altsetting->desc.bInterfaceNumber);
381 for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i ++)
382 printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, intf->cur_altsetting->endpoint[i].desc.bmAttributes, intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
383
384 if (udev->actconfig->desc.bNumInterfaces == 2 && intf->cur_altsetting->desc.bInterfaceNumber == 0)
385 {
386 printk(KERN_INFO "rom interface 0 is not used\n");
387 return -ENODEV;
388 }
389
390 if (intf->cur_altsetting->desc.bInterfaceNumber == 1)
391 {
392 snprintf(devpath, 32, "%d:%s", udev->bus->busnum, udev->devpath);
393 return smsusb1_load_firmware(udev, smscore_registry_getmode(devpath));
394 }
395
396 return smsusb_init_device(intf);
397}
398
399void smsusb_disconnect(struct usb_interface *intf)
400{
401 smsusb_term_device(intf);
402}
403
404static struct usb_device_id smsusb_id_table [] = {
405 { USB_DEVICE(0x187F, 0x0010) },
406 { USB_DEVICE(0x187F, 0x0100) },
407 { USB_DEVICE(0x187F, 0x0200) },
408 { } /* Terminating entry */
409};
410MODULE_DEVICE_TABLE (usb, smsusb_id_table);
411
412static struct usb_driver smsusb_driver = {
413 .name = "smsusb",
414 .probe = smsusb_probe,
415 .disconnect = smsusb_disconnect,
416 .id_table = smsusb_id_table,
417};
418
419int smsusb_register(void)
420{
421 int rc = usb_register(&smsusb_driver);
422 if (rc)
423 printk(KERN_INFO "usb_register failed. Error number %d\n", rc);
424
425 printk(KERN_INFO "%s\n", __FUNCTION__);
426
427 return rc;
428}
429
430void smsusb_unregister(void)
431{
432 /* Regular USB Cleanup */
433 usb_deregister(&smsusb_driver);
434 printk(KERN_INFO "%s\n", __FUNCTION__);
435}
436