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