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