eaa7cf22715b37066b39b63a2e4ce04b59d1907d
[pandora-kernel.git] / drivers / media / dvb / siano / smscoreapi.c
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 #include "sms-cards.h"
36
37 int sms_debug;
38 module_param_named(debug, sms_debug, int, 0644);
39 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
40
41 struct smscore_device_notifyee_t {
42         struct list_head entry;
43         hotplug_t hotplug;
44 };
45
46 struct smscore_idlist_t {
47         struct list_head entry;
48         int             id;
49         int             data_type;
50 };
51
52 struct 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
61 struct 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
96 void smscore_set_board_id(struct smscore_device_t *core, int id)
97 {
98         core->board_id = id;
99 }
100
101 int smscore_get_board_id(struct smscore_device_t *core)
102 {
103         return core->board_id;
104 }
105
106 struct 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
113 struct list_head g_smscore_notifyees;
114 struct list_head g_smscore_devices;
115 kmutex_t g_smscore_deviceslock;
116
117 struct list_head g_smscore_registry;
118 kmutex_t g_smscore_registrylock;
119
120 static int default_mode = 4;
121
122 module_param(default_mode, int, 0644);
123 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
124
125 static 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
153 int 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
166 static 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
179 void 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
190 static 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
203 static 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  */
223 int 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  */
263 void 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
285 static 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
296 static 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
316 static struct
317 smscore_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  */
344 int 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  */
436 int 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
456 static 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
471 static 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  */
587 static 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=%d", 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  */
637 void 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
684 static 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
720 static 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
740 static 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  */
757 int 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_err("error %d loading firmware: %s, "
795                                         "trying again with default firmware",
796                                         rc, fw_filename);
797
798                                 /* try again with the default firmware */
799                                 rc = smscore_load_firmware_from_file(coredev,
800                                         smscore_fw_lkup[mode][type], NULL);
801
802                                 if (rc < 0) {
803                                         sms_err("load firmware failed %d", rc);
804                                         return rc;
805                                 }
806                         }
807                 } else
808                         sms_info("mode %d supported by running "
809                                  "firmware", mode);
810
811                 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
812                                  SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
813                 if (buffer) {
814                         struct SmsMsgData_ST *msg =
815                                 (struct SmsMsgData_ST *)
816                                         SMS_ALIGN_ADDRESS(buffer);
817
818                         SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
819                                      sizeof(struct SmsMsgData_ST));
820                         msg->msgData[0] = mode;
821
822                         rc = smscore_sendrequest_and_wait(
823                                 coredev, msg, msg->xMsgHeader.msgLength,
824                                 &coredev->init_device_done);
825
826                         kfree(buffer);
827                 } else {
828                         sms_err("Could not allocate buffer for "
829                                 "init device message.");
830                         rc = -ENOMEM;
831                 }
832         } else {
833                 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
834                         sms_err("invalid mode specified %d", mode);
835                         return -EINVAL;
836                 }
837
838                 smscore_registry_setmode(coredev->devpath, mode);
839
840                 if (coredev->detectmode_handler)
841                         coredev->detectmode_handler(coredev->context,
842                                                     &coredev->mode);
843
844                 if (coredev->mode != mode && coredev->setmode_handler)
845                         rc = coredev->setmode_handler(coredev->context, mode);
846         }
847
848         if (rc >= 0) {
849                 coredev->mode = mode;
850                 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
851         }
852
853         if (rc != 0)
854                 sms_err("return error code %d.", rc);
855         return rc;
856 }
857
858 /**
859  * calls device handler to get current mode of operation
860  *
861  * @param coredev pointer to a coredev object returned by
862  *                smscore_register_device
863  *
864  * @return current mode
865  */
866 int smscore_get_device_mode(struct smscore_device_t *coredev)
867 {
868         return coredev->mode;
869 }
870
871 /**
872  * find client by response id & type within the clients list.
873  * return client handle or NULL.
874  *
875  * @param coredev pointer to a coredev object returned by
876  *                smscore_register_device
877  * @param data_type client data type (SMS_DONT_CARE for all types)
878  * @param id client id (SMS_DONT_CARE for all id)
879  *
880  */
881 static struct
882 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
883                                       int data_type, int id)
884 {
885         struct smscore_client_t *client = NULL;
886         struct list_head *next, *first;
887         unsigned long flags;
888         struct list_head *firstid, *nextid;
889
890
891         spin_lock_irqsave(&coredev->clientslock, flags);
892         first = &coredev->clients;
893         for (next = first->next;
894              (next != first) && !client;
895              next = next->next) {
896                 firstid = &((struct smscore_client_t *)next)->idlist;
897                 for (nextid = firstid->next;
898                      nextid != firstid;
899                      nextid = nextid->next) {
900                         if ((((struct smscore_idlist_t *)nextid)->id == id) &&
901                             (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
902                             (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
903                                 client = (struct smscore_client_t *) next;
904                                 break;
905                         }
906                 }
907         }
908         spin_unlock_irqrestore(&coredev->clientslock, flags);
909         return client;
910 }
911
912 /**
913  * find client by response id/type, call clients onresponse handler
914  * return buffer to pool on error
915  *
916  * @param coredev pointer to a coredev object returned by
917  *                smscore_register_device
918  * @param cb pointer to response buffer descriptor
919  *
920  */
921 void smscore_onresponse(struct smscore_device_t *coredev,
922                         struct smscore_buffer_t *cb)
923 {
924         struct SmsMsgHdr_ST *phdr =
925                 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
926         struct smscore_client_t *client =
927                 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
928         int rc = -EBUSY;
929
930         static unsigned long last_sample_time; /* = 0; */
931         static int data_total; /* = 0; */
932         unsigned long time_now = jiffies_to_msecs(jiffies);
933
934         if (!last_sample_time)
935                 last_sample_time = time_now;
936
937         if (time_now - last_sample_time > 10000) {
938                 sms_debug("\ndata rate %d bytes/secs",
939                           (int)((data_total * 1000) /
940                                 (time_now - last_sample_time)));
941
942                 last_sample_time = time_now;
943                 data_total = 0;
944         }
945
946         data_total += cb->size;
947         /* If no client registered for type & id,
948          * check for control client where type is not registered */
949         if (client)
950                 rc = client->onresponse_handler(client->context, cb);
951
952         if (rc < 0) {
953                 switch (phdr->msgType) {
954                 case MSG_SMS_GET_VERSION_EX_RES:
955                 {
956                         struct SmsVersionRes_ST *ver =
957                                 (struct SmsVersionRes_ST *) phdr;
958                         sms_debug("MSG_SMS_GET_VERSION_EX_RES "
959                                   "id %d prots 0x%x ver %d.%d",
960                                   ver->FirmwareId, ver->SupportedProtocols,
961                                   ver->RomVersionMajor, ver->RomVersionMinor);
962
963                         coredev->mode = ver->FirmwareId == 255 ?
964                                 DEVICE_MODE_NONE : ver->FirmwareId;
965                         coredev->modes_supported = ver->SupportedProtocols;
966
967                         complete(&coredev->version_ex_done);
968                         break;
969                 }
970                 case MSG_SMS_INIT_DEVICE_RES:
971                         sms_debug("MSG_SMS_INIT_DEVICE_RES");
972                         complete(&coredev->init_device_done);
973                         break;
974                 case MSG_SW_RELOAD_START_RES:
975                         sms_debug("MSG_SW_RELOAD_START_RES");
976                         complete(&coredev->reload_start_done);
977                         break;
978                 case MSG_SMS_DATA_DOWNLOAD_RES:
979                         complete(&coredev->data_download_done);
980                         break;
981                 case MSG_SW_RELOAD_EXEC_RES:
982                         sms_debug("MSG_SW_RELOAD_EXEC_RES");
983                         break;
984                 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
985                         sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
986                         complete(&coredev->trigger_done);
987                         break;
988                 case MSG_SMS_SLEEP_RESUME_COMP_IND:
989                         complete(&coredev->resume_done);
990                         break;
991                 default:
992                         break;
993                 }
994                 smscore_putbuffer(coredev, cb);
995         }
996 }
997
998 /**
999  * return pointer to next free buffer descriptor from core pool
1000  *
1001  * @param coredev pointer to a coredev object returned by
1002  *                smscore_register_device
1003  *
1004  * @return pointer to descriptor on success, NULL on error.
1005  */
1006 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1007 {
1008         struct smscore_buffer_t *cb = NULL;
1009         unsigned long flags;
1010
1011         spin_lock_irqsave(&coredev->bufferslock, flags);
1012
1013         if (!list_empty(&coredev->buffers)) {
1014                 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1015                 list_del(&cb->entry);
1016         }
1017
1018         spin_unlock_irqrestore(&coredev->bufferslock, flags);
1019
1020         return cb;
1021 }
1022
1023 /**
1024  * return buffer descriptor to a pool
1025  *
1026  * @param coredev pointer to a coredev object returned by
1027  *                smscore_register_device
1028  * @param cb pointer buffer descriptor
1029  *
1030  */
1031 void smscore_putbuffer(struct smscore_device_t *coredev,
1032                        struct smscore_buffer_t *cb)
1033 {
1034         list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1035 }
1036
1037 static int smscore_validate_client(struct smscore_device_t *coredev,
1038                                    struct smscore_client_t *client,
1039                                    int data_type, int id)
1040 {
1041         struct smscore_idlist_t *listentry;
1042         struct smscore_client_t *registered_client;
1043
1044         if (!client) {
1045                 sms_err("bad parameter.");
1046                 return -EFAULT;
1047         }
1048         registered_client = smscore_find_client(coredev, data_type, id);
1049         if (registered_client == client)
1050                 return 0;
1051
1052         if (registered_client) {
1053                 sms_err("The msg ID already registered to another client.");
1054                 return -EEXIST;
1055         }
1056         listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1057         if (!listentry) {
1058                 sms_err("Can't allocate memory for client id.");
1059                 return -ENOMEM;
1060         }
1061         listentry->id = id;
1062         listentry->data_type = data_type;
1063         list_add_locked(&listentry->entry, &client->idlist,
1064                         &coredev->clientslock);
1065         return 0;
1066 }
1067
1068 /**
1069  * creates smsclient object, check that id is taken by another client
1070  *
1071  * @param coredev pointer to a coredev object from clients hotplug
1072  * @param initial_id all messages with this id would be sent to this client
1073  * @param data_type all messages of this type would be sent to this client
1074  * @param onresponse_handler client handler that is called to
1075  *                           process incoming messages
1076  * @param onremove_handler client handler that is called when device is removed
1077  * @param context client-specific context
1078  * @param client pointer to a value that receives created smsclient object
1079  *
1080  * @return 0 on success, <0 on error.
1081  */
1082 int smscore_register_client(struct smscore_device_t *coredev,
1083                             struct smsclient_params_t *params,
1084                             struct smscore_client_t **client)
1085 {
1086         struct smscore_client_t *newclient;
1087         /* check that no other channel with same parameters exists */
1088         if (smscore_find_client(coredev, params->data_type,
1089                                 params->initial_id)) {
1090                 sms_err("Client already exist.");
1091                 return -EEXIST;
1092         }
1093
1094         newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1095         if (!newclient) {
1096                 sms_err("Failed to allocate memory for client.");
1097                 return -ENOMEM;
1098         }
1099
1100         INIT_LIST_HEAD(&newclient->idlist);
1101         newclient->coredev = coredev;
1102         newclient->onresponse_handler = params->onresponse_handler;
1103         newclient->onremove_handler = params->onremove_handler;
1104         newclient->context = params->context;
1105         list_add_locked(&newclient->entry, &coredev->clients,
1106                         &coredev->clientslock);
1107         smscore_validate_client(coredev, newclient, params->data_type,
1108                                 params->initial_id);
1109         *client = newclient;
1110         sms_debug("%p %d %d", params->context, params->data_type,
1111                   params->initial_id);
1112
1113         return 0;
1114 }
1115
1116 /**
1117  * frees smsclient object and all subclients associated with it
1118  *
1119  * @param client pointer to smsclient object returned by
1120  *               smscore_register_client
1121  *
1122  */
1123 void smscore_unregister_client(struct smscore_client_t *client)
1124 {
1125         struct smscore_device_t *coredev = client->coredev;
1126         unsigned long flags;
1127
1128         spin_lock_irqsave(&coredev->clientslock, flags);
1129
1130
1131         while (!list_empty(&client->idlist)) {
1132                 struct smscore_idlist_t *identry =
1133                         (struct smscore_idlist_t *) client->idlist.next;
1134                 list_del(&identry->entry);
1135                 kfree(identry);
1136         }
1137
1138         sms_info("%p", client->context);
1139
1140         list_del(&client->entry);
1141         kfree(client);
1142
1143         spin_unlock_irqrestore(&coredev->clientslock, flags);
1144 }
1145
1146 /**
1147  * verifies that source id is not taken by another client,
1148  * calls device handler to send requests to the device
1149  *
1150  * @param client pointer to smsclient object returned by
1151  *               smscore_register_client
1152  * @param buffer pointer to a request buffer
1153  * @param size size (in bytes) of request buffer
1154  *
1155  * @return 0 on success, <0 on error.
1156  */
1157 int smsclient_sendrequest(struct smscore_client_t *client,
1158                           void *buffer, size_t size)
1159 {
1160         struct smscore_device_t *coredev;
1161         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1162         int rc;
1163
1164         if (client == NULL) {
1165                 sms_err("Got NULL client");
1166                 return -EINVAL;
1167         }
1168
1169         coredev = client->coredev;
1170
1171         /* check that no other channel with same id exists */
1172         if (coredev == NULL) {
1173                 sms_err("Got NULL coredev");
1174                 return -EINVAL;
1175         }
1176
1177         rc = smscore_validate_client(client->coredev, client, 0,
1178                                      phdr->msgSrcId);
1179         if (rc < 0)
1180                 return rc;
1181
1182         return coredev->sendrequest_handler(coredev->context, buffer, size);
1183 }
1184
1185
1186 int smscore_module_init(void)
1187 {
1188         int rc = 0;
1189
1190         INIT_LIST_HEAD(&g_smscore_notifyees);
1191         INIT_LIST_HEAD(&g_smscore_devices);
1192         kmutex_init(&g_smscore_deviceslock);
1193
1194         INIT_LIST_HEAD(&g_smscore_registry);
1195         kmutex_init(&g_smscore_registrylock);
1196
1197         /* USB Register */
1198         rc = smsusb_register();
1199
1200         /* DVB Register */
1201         rc = smsdvb_register();
1202
1203         sms_debug("rc %d", rc);
1204
1205         return rc;
1206 }
1207
1208 void smscore_module_exit(void)
1209 {
1210
1211         kmutex_lock(&g_smscore_deviceslock);
1212         while (!list_empty(&g_smscore_notifyees)) {
1213                 struct smscore_device_notifyee_t *notifyee =
1214                         (struct smscore_device_notifyee_t *)
1215                                 g_smscore_notifyees.next;
1216
1217                 list_del(&notifyee->entry);
1218                 kfree(notifyee);
1219         }
1220         kmutex_unlock(&g_smscore_deviceslock);
1221
1222         kmutex_lock(&g_smscore_registrylock);
1223         while (!list_empty(&g_smscore_registry)) {
1224                 struct smscore_registry_entry_t *entry =
1225                         (struct smscore_registry_entry_t *)
1226                                 g_smscore_registry.next;
1227
1228                 list_del(&entry->entry);
1229                 kfree(entry);
1230         }
1231         kmutex_unlock(&g_smscore_registrylock);
1232
1233         /* DVB UnRegister */
1234         smsdvb_unregister();
1235
1236         /* Unregister USB */
1237         smsusb_unregister();
1238
1239         sms_debug("");
1240 }
1241
1242 module_init(smscore_module_init);
1243 module_exit(smscore_module_exit);
1244
1245 MODULE_DESCRIPTION("smscore");
1246 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1247 MODULE_LICENSE("GPL");