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