V4L/DVB (8299): sms1xxx: mark functions static
[linux-2.6] / 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
36 int sms_debug;
37 module_param_named(debug, sms_debug, int, 0644);
38 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
39
40 struct smscore_device_notifyee_t {
41         struct list_head entry;
42         hotplug_t hotplug;
43 };
44
45 struct smscore_idlist_t {
46         struct list_head entry;
47         int             id;
48         int             data_type;
49 };
50
51 struct smscore_client_t {
52         struct list_head entry;
53         struct smscore_device_t *coredev;
54         void                    *context;
55         struct list_head        idlist;
56         onresponse_t    onresponse_handler;
57         onremove_t              onremove_handler;
58 };
59
60 struct smscore_device_t {
61         struct list_head entry;
62
63         struct list_head clients;
64         struct list_head subclients;
65         spinlock_t              clientslock;
66
67         struct list_head buffers;
68         spinlock_t              bufferslock;
69         int                             num_buffers;
70
71         void                    *common_buffer;
72         int                             common_buffer_size;
73         dma_addr_t              common_buffer_phys;
74
75         void                    *context;
76         struct device   *device;
77
78         char                    devpath[32];
79         unsigned long   device_flags;
80
81         setmode_t               setmode_handler;
82         detectmode_t    detectmode_handler;
83         sendrequest_t   sendrequest_handler;
84         preload_t               preload_handler;
85         postload_t              postload_handler;
86
87         int                             mode, modes_supported;
88
89         struct completion version_ex_done, data_download_done, trigger_done;
90         struct completion init_device_done, reload_start_done, resume_done;
91
92         int board_id;
93 };
94
95 void smscore_set_board_id(struct smscore_device_t *core, int id)
96 {
97         core->board_id = id;
98 }
99
100 int smscore_get_board_id(struct smscore_device_t *core)
101 {
102         return core->board_id;
103 }
104
105 struct smscore_registry_entry_t {
106         struct list_head entry;
107         char                    devpath[32];
108         int                             mode;
109         enum sms_device_type_st type;
110 };
111
112 struct list_head g_smscore_notifyees;
113 struct list_head g_smscore_devices;
114 kmutex_t g_smscore_deviceslock;
115
116 struct list_head g_smscore_registry;
117 kmutex_t g_smscore_registrylock;
118
119 static int default_mode = 4;
120
121 module_param(default_mode, int, 0644);
122 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
123
124 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
125 {
126         struct smscore_registry_entry_t *entry;
127         struct list_head *next;
128
129         kmutex_lock(&g_smscore_registrylock);
130         for (next = g_smscore_registry.next;
131              next != &g_smscore_registry;
132              next = next->next) {
133                 entry = (struct smscore_registry_entry_t *) next;
134                 if (!strcmp(entry->devpath, devpath)) {
135                         kmutex_unlock(&g_smscore_registrylock);
136                         return entry;
137                 }
138         }
139         entry = (struct smscore_registry_entry_t *)
140                         kmalloc(sizeof(struct smscore_registry_entry_t),
141                                 GFP_KERNEL);
142         if (entry) {
143                 entry->mode = default_mode;
144                 strcpy(entry->devpath, devpath);
145                 list_add(&entry->entry, &g_smscore_registry);
146         } else
147                 sms_err("failed to create smscore_registry.");
148         kmutex_unlock(&g_smscore_registrylock);
149         return entry;
150 }
151
152 int smscore_registry_getmode(char *devpath)
153 {
154         struct smscore_registry_entry_t *entry;
155
156         entry = smscore_find_registry(devpath);
157         if (entry)
158                 return entry->mode;
159         else
160                 sms_err("No registry found.");
161
162         return default_mode;
163 }
164
165 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
166 {
167         struct smscore_registry_entry_t *entry;
168
169         entry = smscore_find_registry(devpath);
170         if (entry)
171                 return entry->type;
172         else
173                 sms_err("No registry found.");
174
175         return -1;
176 }
177
178 void smscore_registry_setmode(char *devpath, int mode)
179 {
180         struct smscore_registry_entry_t *entry;
181
182         entry = smscore_find_registry(devpath);
183         if (entry)
184                 entry->mode = mode;
185         else
186                 sms_err("No registry found.");
187 }
188
189 static void smscore_registry_settype(char *devpath,
190                                      enum sms_device_type_st type)
191 {
192         struct smscore_registry_entry_t *entry;
193
194         entry = smscore_find_registry(devpath);
195         if (entry)
196                 entry->type = type;
197         else
198                 sms_err("No registry found.");
199 }
200
201
202 static void list_add_locked(struct list_head *new, struct list_head *head,
203                             spinlock_t *lock)
204 {
205         unsigned long flags;
206
207         spin_lock_irqsave(lock, flags);
208
209         list_add(new, head);
210
211         spin_unlock_irqrestore(lock, flags);
212 }
213
214 /**
215  * register a client callback that called when device plugged in/unplugged
216  * NOTE: if devices exist callback is called immediately for each device
217  *
218  * @param hotplug callback
219  *
220  * @return 0 on success, <0 on error.
221  */
222 int smscore_register_hotplug(hotplug_t hotplug)
223 {
224         struct smscore_device_notifyee_t *notifyee;
225         struct list_head *next, *first;
226         int rc = 0;
227
228         kmutex_lock(&g_smscore_deviceslock);
229
230         notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
231                            GFP_KERNEL);
232         if (notifyee) {
233                 /* now notify callback about existing devices */
234                 first = &g_smscore_devices;
235                 for (next = first->next;
236                      next != first && !rc;
237                      next = next->next) {
238                         struct smscore_device_t *coredev =
239                                 (struct smscore_device_t *) next;
240                         rc = hotplug(coredev, coredev->device, 1);
241                 }
242
243                 if (rc >= 0) {
244                         notifyee->hotplug = hotplug;
245                         list_add(&notifyee->entry, &g_smscore_notifyees);
246                 } else
247                         kfree(notifyee);
248         } else
249                 rc = -ENOMEM;
250
251         kmutex_unlock(&g_smscore_deviceslock);
252
253         return rc;
254 }
255
256 /**
257  * unregister a client callback that called when device plugged in/unplugged
258  *
259  * @param hotplug callback
260  *
261  */
262 void smscore_unregister_hotplug(hotplug_t hotplug)
263 {
264         struct list_head *next, *first;
265
266         kmutex_lock(&g_smscore_deviceslock);
267
268         first = &g_smscore_notifyees;
269
270         for (next = first->next; next != first;) {
271                 struct smscore_device_notifyee_t *notifyee =
272                         (struct smscore_device_notifyee_t *) next;
273                 next = next->next;
274
275                 if (notifyee->hotplug == hotplug) {
276                         list_del(&notifyee->entry);
277                         kfree(notifyee);
278                 }
279         }
280
281         kmutex_unlock(&g_smscore_deviceslock);
282 }
283
284 static void smscore_notify_clients(struct smscore_device_t *coredev)
285 {
286         struct smscore_client_t *client;
287
288         /* the client must call smscore_unregister_client from remove handler */
289         while (!list_empty(&coredev->clients)) {
290                 client = (struct smscore_client_t *) coredev->clients.next;
291                 client->onremove_handler(client->context);
292         }
293 }
294
295 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
296                                     struct device *device, int arrival)
297 {
298         struct list_head *next, *first;
299         int rc = 0;
300
301         /* note: must be called under g_deviceslock */
302
303         first = &g_smscore_notifyees;
304
305         for (next = first->next; next != first; next = next->next) {
306                 rc = ((struct smscore_device_notifyee_t *) next)->
307                                 hotplug(coredev, device, arrival);
308                 if (rc < 0)
309                         break;
310         }
311
312         return rc;
313 }
314
315 static struct
316 smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
317                                        dma_addr_t common_buffer_phys)
318 {
319         struct smscore_buffer_t *cb =
320                 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
321         if (!cb) {
322                 sms_info("kmalloc(...) failed");
323                 return NULL;
324         }
325
326         cb->p = buffer;
327         cb->offset_in_common = buffer - (u8 *) common_buffer;
328         cb->phys = common_buffer_phys + cb->offset_in_common;
329
330         return cb;
331 }
332
333 /**
334  * creates coredev object for a device, prepares buffers,
335  * creates buffer mappings, notifies registered hotplugs about new device.
336  *
337  * @param params device pointer to struct with device specific parameters
338  *               and handlers
339  * @param coredev pointer to a value that receives created coredev object
340  *
341  * @return 0 on success, <0 on error.
342  */
343 int smscore_register_device(struct smsdevice_params_t *params,
344                             struct smscore_device_t **coredev)
345 {
346         struct smscore_device_t *dev;
347         u8 *buffer;
348
349         dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
350         if (!dev) {
351                 sms_info("kzalloc(...) failed");
352                 return -ENOMEM;
353         }
354
355         /* init list entry so it could be safe in smscore_unregister_device */
356         INIT_LIST_HEAD(&dev->entry);
357
358         /* init queues */
359         INIT_LIST_HEAD(&dev->clients);
360         INIT_LIST_HEAD(&dev->buffers);
361
362         /* init locks */
363         spin_lock_init(&dev->clientslock);
364         spin_lock_init(&dev->bufferslock);
365
366         /* init completion events */
367         init_completion(&dev->version_ex_done);
368         init_completion(&dev->data_download_done);
369         init_completion(&dev->trigger_done);
370         init_completion(&dev->init_device_done);
371         init_completion(&dev->reload_start_done);
372         init_completion(&dev->resume_done);
373
374         /* alloc common buffer */
375         dev->common_buffer_size = params->buffer_size * params->num_buffers;
376         dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
377                                                 &dev->common_buffer_phys,
378                                                 GFP_KERNEL | GFP_DMA);
379         if (!dev->common_buffer) {
380                 smscore_unregister_device(dev);
381                 return -ENOMEM;
382         }
383
384         /* prepare dma buffers */
385         for (buffer = dev->common_buffer;
386              dev->num_buffers < params->num_buffers;
387              dev->num_buffers++, buffer += params->buffer_size) {
388                 struct smscore_buffer_t *cb =
389                         smscore_createbuffer(buffer, dev->common_buffer,
390                                              dev->common_buffer_phys);
391                 if (!cb) {
392                         smscore_unregister_device(dev);
393                         return -ENOMEM;
394                 }
395
396                 smscore_putbuffer(dev, cb);
397         }
398
399         sms_info("allocated %d buffers", dev->num_buffers);
400
401         dev->mode = DEVICE_MODE_NONE;
402         dev->context = params->context;
403         dev->device = params->device;
404         dev->setmode_handler = params->setmode_handler;
405         dev->detectmode_handler = params->detectmode_handler;
406         dev->sendrequest_handler = params->sendrequest_handler;
407         dev->preload_handler = params->preload_handler;
408         dev->postload_handler = params->postload_handler;
409
410         dev->device_flags = params->flags;
411         strcpy(dev->devpath, params->devpath);
412
413         smscore_registry_settype(dev->devpath, params->device_type);
414
415         /* add device to devices list */
416         kmutex_lock(&g_smscore_deviceslock);
417         list_add(&dev->entry, &g_smscore_devices);
418         kmutex_unlock(&g_smscore_deviceslock);
419
420         *coredev = dev;
421
422         sms_info("device %p created", dev);
423
424         return 0;
425 }
426
427 /**
428  * sets initial device mode and notifies client hotplugs that device is ready
429  *
430  * @param coredev pointer to a coredev object returned by
431  *                smscore_register_device
432  *
433  * @return 0 on success, <0 on error.
434  */
435 int smscore_start_device(struct smscore_device_t *coredev)
436 {
437         int rc = smscore_set_device_mode(
438                         coredev, smscore_registry_getmode(coredev->devpath));
439         if (rc < 0) {
440                 sms_info("set device mode faile , rc %d", rc);
441                 return rc;
442         }
443
444         kmutex_lock(&g_smscore_deviceslock);
445
446         rc = smscore_notify_callbacks(coredev, coredev->device, 1);
447
448         sms_info("device %p started, rc %d", coredev, rc);
449
450         kmutex_unlock(&g_smscore_deviceslock);
451
452         return rc;
453 }
454
455 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
456                                         void *buffer, size_t size,
457                                         struct completion *completion)
458 {
459         int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
460         if (rc < 0) {
461                 sms_info("sendrequest returned error %d", rc);
462                 return rc;
463         }
464
465         return wait_for_completion_timeout(completion,
466                                            msecs_to_jiffies(10000)) ?
467                                                 0 : -ETIME;
468 }
469
470 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
471                                          void *buffer, size_t size)
472 {
473         struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
474         struct SmsMsgHdr_ST *msg;
475         u32 mem_address = firmware->StartAddress;
476         u8 *payload = firmware->Payload;
477         int rc = 0;
478
479         sms_info("loading FW to addr 0x%x size %d",
480                  mem_address, firmware->Length);
481         if (coredev->preload_handler) {
482                 rc = coredev->preload_handler(coredev->context);
483                 if (rc < 0)
484                         return rc;
485         }
486
487         /* PAGE_SIZE buffer shall be enough and dma aligned */
488         msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
489         if (!msg)
490                 return -ENOMEM;
491
492         if (coredev->mode != DEVICE_MODE_NONE) {
493                 sms_debug("sending reload command.");
494                 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
495                              sizeof(struct SmsMsgHdr_ST));
496                 rc = smscore_sendrequest_and_wait(coredev, msg,
497                                                   msg->msgLength,
498                                                   &coredev->reload_start_done);
499                 mem_address = *(u32 *) &payload[20];
500         }
501
502         while (size && rc >= 0) {
503                 struct SmsDataDownload_ST *DataMsg =
504                         (struct SmsDataDownload_ST *) msg;
505                 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
506
507                 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
508                              (u16)(sizeof(struct SmsMsgHdr_ST) +
509                                       sizeof(u32) + payload_size));
510
511                 DataMsg->MemAddr = mem_address;
512                 memcpy(DataMsg->Payload, payload, payload_size);
513
514                 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
515                     (coredev->mode == DEVICE_MODE_NONE))
516                         rc = coredev->sendrequest_handler(
517                                 coredev->context, DataMsg,
518                                 DataMsg->xMsgHeader.msgLength);
519                 else
520                         rc = smscore_sendrequest_and_wait(
521                                 coredev, DataMsg,
522                                 DataMsg->xMsgHeader.msgLength,
523                                 &coredev->data_download_done);
524
525                 payload += payload_size;
526                 size -= payload_size;
527                 mem_address += payload_size;
528         }
529
530         if (rc >= 0) {
531                 if (coredev->mode == DEVICE_MODE_NONE) {
532                         struct SmsMsgData_ST *TriggerMsg =
533                                 (struct SmsMsgData_ST *) msg;
534
535                         SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
536                                      sizeof(struct SmsMsgHdr_ST) +
537                                      sizeof(u32) * 5);
538
539                         TriggerMsg->msgData[0] = firmware->StartAddress;
540                                                 /* Entry point */
541                         TriggerMsg->msgData[1] = 5; /* Priority */
542                         TriggerMsg->msgData[2] = 0x200; /* Stack size */
543                         TriggerMsg->msgData[3] = 0; /* Parameter */
544                         TriggerMsg->msgData[4] = 4; /* Task ID */
545
546                         if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
547                                 rc = coredev->sendrequest_handler(
548                                         coredev->context, TriggerMsg,
549                                         TriggerMsg->xMsgHeader.msgLength);
550                                 msleep(100);
551                         } else
552                                 rc = smscore_sendrequest_and_wait(
553                                         coredev, TriggerMsg,
554                                         TriggerMsg->xMsgHeader.msgLength,
555                                         &coredev->trigger_done);
556                 } else {
557                         SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
558                                      sizeof(struct SmsMsgHdr_ST));
559
560                         rc = coredev->sendrequest_handler(coredev->context,
561                                                           msg, msg->msgLength);
562                 }
563                 msleep(500);
564         }
565
566         sms_debug("rc=%d, postload=%p ", rc,
567                   coredev->postload_handler);
568
569         kfree(msg);
570
571         return ((rc >= 0) && coredev->postload_handler) ?
572                 coredev->postload_handler(coredev->context) :
573                 rc;
574 }
575
576 /**
577  * loads specified firmware into a buffer and calls device loadfirmware_handler
578  *
579  * @param coredev pointer to a coredev object returned by
580  *                smscore_register_device
581  * @param filename null-terminated string specifies firmware file name
582  * @param loadfirmware_handler device handler that loads firmware
583  *
584  * @return 0 on success, <0 on error.
585  */
586 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
587                                            char *filename,
588                                            loadfirmware_t loadfirmware_handler)
589 {
590         int rc = -ENOENT;
591         const struct firmware *fw;
592         u8 *fw_buffer;
593
594         if (loadfirmware_handler == NULL && !(coredev->device_flags &
595                                               SMS_DEVICE_FAMILY2))
596                 return -EINVAL;
597
598         rc = request_firmware(&fw, filename, coredev->device);
599         if (rc < 0) {
600                 sms_info("failed to open \"%s\"", filename);
601                 return rc;
602         }
603         sms_info("read FW %s, size=%d\"", filename, fw->size);
604         fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
605                             GFP_KERNEL | GFP_DMA);
606         if (fw_buffer) {
607                 memcpy(fw_buffer, fw->data, fw->size);
608
609                 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
610                       smscore_load_firmware_family2(coredev,
611                                                     fw_buffer,
612                                                     fw->size) :
613                       loadfirmware_handler(coredev->context,
614                                            fw_buffer, fw->size);
615
616                 kfree(fw_buffer);
617         } else {
618                 sms_info("failed to allocate firmware buffer");
619                 rc = -ENOMEM;
620         }
621
622         release_firmware(fw);
623
624         return rc;
625 }
626
627 /**
628  * notifies all clients registered with the device, notifies hotplugs,
629  * frees all buffers and coredev object
630  *
631  * @param coredev pointer to a coredev object returned by
632  *                smscore_register_device
633  *
634  * @return 0 on success, <0 on error.
635  */
636 void smscore_unregister_device(struct smscore_device_t *coredev)
637 {
638         struct smscore_buffer_t *cb;
639         int num_buffers = 0;
640         int retry = 0;
641
642         kmutex_lock(&g_smscore_deviceslock);
643
644         smscore_notify_clients(coredev);
645         smscore_notify_callbacks(coredev, NULL, 0);
646
647         /* at this point all buffers should be back
648          * onresponse must no longer be called */
649
650         while (1) {
651                 while ((cb = smscore_getbuffer(coredev))) {
652                         kfree(cb);
653                         num_buffers++;
654                 }
655                 if (num_buffers == coredev->num_buffers)
656                         break;
657                 if (++retry > 10) {
658                         sms_info("exiting although "
659                                  "not all buffers released.");
660                         break;
661                 }
662
663                 sms_info("waiting for %d buffer(s)",
664                          coredev->num_buffers - num_buffers);
665                 msleep(100);
666         }
667
668         sms_info("freed %d buffers", num_buffers);
669
670         if (coredev->common_buffer)
671                 dma_free_coherent(NULL, coredev->common_buffer_size,
672                                   coredev->common_buffer,
673                                   coredev->common_buffer_phys);
674
675         list_del(&coredev->entry);
676         kfree(coredev);
677
678         kmutex_unlock(&g_smscore_deviceslock);
679
680         sms_info("device %p destroyed", coredev);
681 }
682
683 static int smscore_detect_mode(struct smscore_device_t *coredev)
684 {
685         void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
686                                GFP_KERNEL | GFP_DMA);
687         struct SmsMsgHdr_ST *msg =
688                 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
689         int rc;
690
691         if (!buffer)
692                 return -ENOMEM;
693
694         SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
695                      sizeof(struct SmsMsgHdr_ST));
696
697         rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
698                                           &coredev->version_ex_done);
699         if (rc == -ETIME) {
700                 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
701
702                 if (wait_for_completion_timeout(&coredev->resume_done,
703                                                 msecs_to_jiffies(5000))) {
704                         rc = smscore_sendrequest_and_wait(
705                                 coredev, msg, msg->msgLength,
706                                 &coredev->version_ex_done);
707                         if (rc < 0)
708                                 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
709                                         "second try, rc %d", rc);
710                 } else
711                         rc = -ETIME;
712         }
713
714         kfree(buffer);
715
716         return rc;
717 }
718
719 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
720         /*Stellar               NOVA A0         Nova B0         VEGA*/
721         /*DVBT*/
722         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
723         /*DVBH*/
724         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
725         /*TDMB*/
726         {"none", "tdmb_nova_12mhz.inp", "none", "none"},
727         /*DABIP*/
728         {"none", "none", "none", "none"},
729         /*BDA*/
730         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
731         /*ISDBT*/
732         {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
733         /*ISDBTBDA*/
734         {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
735         /*CMMB*/
736         {"none", "none", "none", "cmmb_vega_12mhz.inp"}
737 };
738
739
740 /**
741  * calls device handler to change mode of operation
742  * NOTE: stellar/usb may disconnect when changing mode
743  *
744  * @param coredev pointer to a coredev object returned by
745  *                smscore_register_device
746  * @param mode requested mode of operation
747  *
748  * @return 0 on success, <0 on error.
749  */
750 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
751 {
752         void *buffer;
753         int rc = 0;
754         enum sms_device_type_st type;
755
756         sms_debug("set device mode to %d", mode);
757         if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
758                 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
759                         sms_err("invalid mode specified %d", mode);
760                         return -EINVAL;
761                 }
762
763                 smscore_registry_setmode(coredev->devpath, mode);
764
765                 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
766                         rc = smscore_detect_mode(coredev);
767                         if (rc < 0) {
768                                 sms_err("mode detect failed %d", rc);
769                                 return rc;
770                         }
771                 }
772
773                 if (coredev->mode == mode) {
774                         sms_info("device mode %d already set", mode);
775                         return 0;
776                 }
777
778                 if (!(coredev->modes_supported & (1 << mode))) {
779                         type = smscore_registry_gettype(coredev->devpath);
780                         rc = smscore_load_firmware_from_file(
781                                 coredev, smscore_fw_lkup[mode][type], NULL);
782                         if (rc < 0) {
783                                 sms_err("load firmware failed %d", rc);
784                                 return rc;
785                         }
786                 } else
787                         sms_info("mode %d supported by running "
788                                  "firmware", mode);
789
790                 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
791                                  SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
792                 if (buffer) {
793                         struct SmsMsgData_ST *msg =
794                                 (struct SmsMsgData_ST *)
795                                         SMS_ALIGN_ADDRESS(buffer);
796
797                         SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
798                                      sizeof(struct SmsMsgData_ST));
799                         msg->msgData[0] = mode;
800
801                         rc = smscore_sendrequest_and_wait(
802                                 coredev, msg, msg->xMsgHeader.msgLength,
803                                 &coredev->init_device_done);
804
805                         kfree(buffer);
806                 } else {
807                         sms_err("Could not allocate buffer for "
808                                 "init device message.");
809                         rc = -ENOMEM;
810                 }
811         } else {
812                 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
813                         sms_err("invalid mode specified %d", mode);
814                         return -EINVAL;
815                 }
816
817                 smscore_registry_setmode(coredev->devpath, mode);
818
819                 if (coredev->detectmode_handler)
820                         coredev->detectmode_handler(coredev->context,
821                                                     &coredev->mode);
822
823                 if (coredev->mode != mode && coredev->setmode_handler)
824                         rc = coredev->setmode_handler(coredev->context, mode);
825         }
826
827         if (rc >= 0) {
828                 coredev->mode = mode;
829                 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
830         }
831
832         if (rc != 0)
833                 sms_err("return error code %d.", rc);
834         return rc;
835 }
836
837 /**
838  * calls device handler to get current mode of operation
839  *
840  * @param coredev pointer to a coredev object returned by
841  *                smscore_register_device
842  *
843  * @return current mode
844  */
845 int smscore_get_device_mode(struct smscore_device_t *coredev)
846 {
847         return coredev->mode;
848 }
849
850 /**
851  * find client by response id & type within the clients list.
852  * return client handle or NULL.
853  *
854  * @param coredev pointer to a coredev object returned by
855  *                smscore_register_device
856  * @param data_type client data type (SMS_DONT_CARE for all types)
857  * @param id client id (SMS_DONT_CARE for all id)
858  *
859  */
860 static struct
861 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
862                                       int data_type, int id)
863 {
864         struct smscore_client_t *client = NULL;
865         struct list_head *next, *first;
866         unsigned long flags;
867         struct list_head *firstid, *nextid;
868
869
870         spin_lock_irqsave(&coredev->clientslock, flags);
871         first = &coredev->clients;
872         for (next = first->next;
873              (next != first) && !client;
874              next = next->next) {
875                 firstid = &((struct smscore_client_t *)next)->idlist;
876                 for (nextid = firstid->next;
877                      nextid != firstid;
878                      nextid = nextid->next) {
879                         if ((((struct smscore_idlist_t *)nextid)->id == id) &&
880                             (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
881                             (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
882                                 client = (struct smscore_client_t *) next;
883                                 break;
884                         }
885                 }
886         }
887         spin_unlock_irqrestore(&coredev->clientslock, flags);
888         return client;
889 }
890
891 /**
892  * find client by response id/type, call clients onresponse handler
893  * return buffer to pool on error
894  *
895  * @param coredev pointer to a coredev object returned by
896  *                smscore_register_device
897  * @param cb pointer to response buffer descriptor
898  *
899  */
900 void smscore_onresponse(struct smscore_device_t *coredev,
901                         struct smscore_buffer_t *cb)
902 {
903         struct SmsMsgHdr_ST *phdr =
904                 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
905         struct smscore_client_t *client =
906                 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
907         int rc = -EBUSY;
908
909         static unsigned long last_sample_time; /* = 0; */
910         static int data_total; /* = 0; */
911         unsigned long time_now = jiffies_to_msecs(jiffies);
912
913         if (!last_sample_time)
914                 last_sample_time = time_now;
915
916         if (time_now - last_sample_time > 10000) {
917                 sms_debug("\ndata rate %d bytes/secs",
918                           (int)((data_total * 1000) /
919                                 (time_now - last_sample_time)));
920
921                 last_sample_time = time_now;
922                 data_total = 0;
923         }
924
925         data_total += cb->size;
926         /* If no client registered for type & id,
927          * check for control client where type is not registered */
928         if (client)
929                 rc = client->onresponse_handler(client->context, cb);
930
931         if (rc < 0) {
932                 switch (phdr->msgType) {
933                 case MSG_SMS_GET_VERSION_EX_RES:
934                 {
935                         struct SmsVersionRes_ST *ver =
936                                 (struct SmsVersionRes_ST *) phdr;
937                         sms_debug("MSG_SMS_GET_VERSION_EX_RES "
938                                   "id %d prots 0x%x ver %d.%d",
939                                   ver->FirmwareId, ver->SupportedProtocols,
940                                   ver->RomVersionMajor, ver->RomVersionMinor);
941
942                         coredev->mode = ver->FirmwareId == 255 ?
943                                 DEVICE_MODE_NONE : ver->FirmwareId;
944                         coredev->modes_supported = ver->SupportedProtocols;
945
946                         complete(&coredev->version_ex_done);
947                         break;
948                 }
949                 case MSG_SMS_INIT_DEVICE_RES:
950                         sms_debug("MSG_SMS_INIT_DEVICE_RES");
951                         complete(&coredev->init_device_done);
952                         break;
953                 case MSG_SW_RELOAD_START_RES:
954                         sms_debug("MSG_SW_RELOAD_START_RES");
955                         complete(&coredev->reload_start_done);
956                         break;
957                 case MSG_SMS_DATA_DOWNLOAD_RES:
958                         complete(&coredev->data_download_done);
959                         break;
960                 case MSG_SW_RELOAD_EXEC_RES:
961                         sms_debug("MSG_SW_RELOAD_EXEC_RES");
962                         break;
963                 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
964                         sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
965                         complete(&coredev->trigger_done);
966                         break;
967                 case MSG_SMS_SLEEP_RESUME_COMP_IND:
968                         complete(&coredev->resume_done);
969                         break;
970                 default:
971                         break;
972                 }
973                 smscore_putbuffer(coredev, cb);
974         }
975 }
976
977 /**
978  * return pointer to next free buffer descriptor from core pool
979  *
980  * @param coredev pointer to a coredev object returned by
981  *                smscore_register_device
982  *
983  * @return pointer to descriptor on success, NULL on error.
984  */
985 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
986 {
987         struct smscore_buffer_t *cb = NULL;
988         unsigned long flags;
989
990         spin_lock_irqsave(&coredev->bufferslock, flags);
991
992         if (!list_empty(&coredev->buffers)) {
993                 cb = (struct smscore_buffer_t *) coredev->buffers.next;
994                 list_del(&cb->entry);
995         }
996
997         spin_unlock_irqrestore(&coredev->bufferslock, flags);
998
999         return cb;
1000 }
1001
1002 /**
1003  * return buffer descriptor to a pool
1004  *
1005  * @param coredev pointer to a coredev object returned by
1006  *                smscore_register_device
1007  * @param cb pointer buffer descriptor
1008  *
1009  */
1010 void smscore_putbuffer(struct smscore_device_t *coredev,
1011                        struct smscore_buffer_t *cb)
1012 {
1013         list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1014 }
1015
1016 static int smscore_validate_client(struct smscore_device_t *coredev,
1017                                    struct smscore_client_t *client,
1018                                    int data_type, int id)
1019 {
1020         struct smscore_idlist_t *listentry;
1021         struct smscore_client_t *registered_client;
1022
1023         if (!client) {
1024                 sms_err("bad parameter.");
1025                 return -EFAULT;
1026         }
1027         registered_client = smscore_find_client(coredev, data_type, id);
1028         if (registered_client == client)
1029                 return 0;
1030
1031         if (registered_client) {
1032                 sms_err("The msg ID already registered to another client.");
1033                 return -EEXIST;
1034         }
1035         listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1036         if (!listentry) {
1037                 sms_err("Can't allocate memory for client id.");
1038                 return -ENOMEM;
1039         }
1040         listentry->id = id;
1041         listentry->data_type = data_type;
1042         list_add_locked(&listentry->entry, &client->idlist,
1043                         &coredev->clientslock);
1044         return 0;
1045 }
1046
1047 /**
1048  * creates smsclient object, check that id is taken by another client
1049  *
1050  * @param coredev pointer to a coredev object from clients hotplug
1051  * @param initial_id all messages with this id would be sent to this client
1052  * @param data_type all messages of this type would be sent to this client
1053  * @param onresponse_handler client handler that is called to
1054  *                           process incoming messages
1055  * @param onremove_handler client handler that is called when device is removed
1056  * @param context client-specific context
1057  * @param client pointer to a value that receives created smsclient object
1058  *
1059  * @return 0 on success, <0 on error.
1060  */
1061 int smscore_register_client(struct smscore_device_t *coredev,
1062                             struct smsclient_params_t *params,
1063                             struct smscore_client_t **client)
1064 {
1065         struct smscore_client_t *newclient;
1066         /* check that no other channel with same parameters exists */
1067         if (smscore_find_client(coredev, params->data_type,
1068                                 params->initial_id)) {
1069                 sms_err("Client already exist.");
1070                 return -EEXIST;
1071         }
1072
1073         newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1074         if (!newclient) {
1075                 sms_err("Failed to allocate memory for client.");
1076                 return -ENOMEM;
1077         }
1078
1079         INIT_LIST_HEAD(&newclient->idlist);
1080         newclient->coredev = coredev;
1081         newclient->onresponse_handler = params->onresponse_handler;
1082         newclient->onremove_handler = params->onremove_handler;
1083         newclient->context = params->context;
1084         list_add_locked(&newclient->entry, &coredev->clients,
1085                         &coredev->clientslock);
1086         smscore_validate_client(coredev, newclient, params->data_type,
1087                                 params->initial_id);
1088         *client = newclient;
1089         sms_debug("%p %d %d", params->context, params->data_type,
1090                   params->initial_id);
1091
1092         return 0;
1093 }
1094
1095 /**
1096  * frees smsclient object and all subclients associated with it
1097  *
1098  * @param client pointer to smsclient object returned by
1099  *               smscore_register_client
1100  *
1101  */
1102 void smscore_unregister_client(struct smscore_client_t *client)
1103 {
1104         struct smscore_device_t *coredev = client->coredev;
1105         unsigned long flags;
1106
1107         spin_lock_irqsave(&coredev->clientslock, flags);
1108
1109
1110         while (!list_empty(&client->idlist)) {
1111                 struct smscore_idlist_t *identry =
1112                         (struct smscore_idlist_t *) client->idlist.next;
1113                 list_del(&identry->entry);
1114                 kfree(identry);
1115         }
1116
1117         sms_info("%p", client->context);
1118
1119         list_del(&client->entry);
1120         kfree(client);
1121
1122         spin_unlock_irqrestore(&coredev->clientslock, flags);
1123 }
1124
1125 /**
1126  * verifies that source id is not taken by another client,
1127  * calls device handler to send requests to the device
1128  *
1129  * @param client pointer to smsclient object returned by
1130  *               smscore_register_client
1131  * @param buffer pointer to a request buffer
1132  * @param size size (in bytes) of request buffer
1133  *
1134  * @return 0 on success, <0 on error.
1135  */
1136 int smsclient_sendrequest(struct smscore_client_t *client,
1137                           void *buffer, size_t size)
1138 {
1139         struct smscore_device_t *coredev;
1140         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1141         int rc;
1142
1143         if (client == NULL) {
1144                 sms_err("Got NULL client");
1145                 return -EINVAL;
1146         }
1147
1148         coredev = client->coredev;
1149
1150         /* check that no other channel with same id exists */
1151         if (coredev == NULL) {
1152                 sms_err("Got NULL coredev");
1153                 return -EINVAL;
1154         }
1155
1156         rc = smscore_validate_client(client->coredev, client, 0,
1157                                      phdr->msgSrcId);
1158         if (rc < 0)
1159                 return rc;
1160
1161         return coredev->sendrequest_handler(coredev->context, buffer, size);
1162 }
1163
1164
1165 int smscore_module_init(void)
1166 {
1167         int rc = 0;
1168
1169         INIT_LIST_HEAD(&g_smscore_notifyees);
1170         INIT_LIST_HEAD(&g_smscore_devices);
1171         kmutex_init(&g_smscore_deviceslock);
1172
1173         INIT_LIST_HEAD(&g_smscore_registry);
1174         kmutex_init(&g_smscore_registrylock);
1175
1176         /* USB Register */
1177         rc = smsusb_register();
1178
1179         /* DVB Register */
1180         rc = smsdvb_register();
1181
1182         sms_debug("rc %d", rc);
1183
1184         return rc;
1185 }
1186
1187 void smscore_module_exit(void)
1188 {
1189
1190         kmutex_lock(&g_smscore_deviceslock);
1191         while (!list_empty(&g_smscore_notifyees)) {
1192                 struct smscore_device_notifyee_t *notifyee =
1193                         (struct smscore_device_notifyee_t *)
1194                                 g_smscore_notifyees.next;
1195
1196                 list_del(&notifyee->entry);
1197                 kfree(notifyee);
1198         }
1199         kmutex_unlock(&g_smscore_deviceslock);
1200
1201         kmutex_lock(&g_smscore_registrylock);
1202         while (!list_empty(&g_smscore_registry)) {
1203                 struct smscore_registry_entry_t *entry =
1204                         (struct smscore_registry_entry_t *)
1205                                 g_smscore_registry.next;
1206
1207                 list_del(&entry->entry);
1208                 kfree(entry);
1209         }
1210         kmutex_unlock(&g_smscore_registrylock);
1211
1212         /* DVB UnRegister */
1213         smsdvb_unregister();
1214
1215         /* Unregister USB */
1216         smsusb_unregister();
1217
1218         sms_debug("");
1219 }
1220
1221 module_init(smscore_module_init);
1222 module_exit(smscore_module_exit);
1223
1224 MODULE_DESCRIPTION("smscore");
1225 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1226 MODULE_LICENSE("GPL");