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