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