ima: fix bug in argument order
[sfrench/cifs-2.6.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 #include <linux/slab.h>
32
33 #include <linux/firmware.h>
34 #include <linux/wait.h>
35 #include <asm/byteorder.h>
36
37 #include "smscoreapi.h"
38 #include "sms-cards.h"
39 #include "smsir.h"
40 #include "smsendian.h"
41
42 static int sms_dbg;
43 module_param_named(debug, sms_dbg, int, 0644);
44 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
45
46 struct smscore_device_notifyee_t {
47         struct list_head entry;
48         hotplug_t hotplug;
49 };
50
51 struct smscore_idlist_t {
52         struct list_head entry;
53         int             id;
54         int             data_type;
55 };
56
57 struct smscore_client_t {
58         struct list_head entry;
59         struct smscore_device_t *coredev;
60         void                    *context;
61         struct list_head        idlist;
62         onresponse_t    onresponse_handler;
63         onremove_t              onremove_handler;
64 };
65
66 void smscore_set_board_id(struct smscore_device_t *core, int id)
67 {
68         core->board_id = id;
69 }
70
71 int smscore_led_state(struct smscore_device_t *core, int led)
72 {
73         if (led >= 0)
74                 core->led_state = led;
75         return core->led_state;
76 }
77 EXPORT_SYMBOL_GPL(smscore_set_board_id);
78
79 int smscore_get_board_id(struct smscore_device_t *core)
80 {
81         return core->board_id;
82 }
83 EXPORT_SYMBOL_GPL(smscore_get_board_id);
84
85 struct smscore_registry_entry_t {
86         struct list_head entry;
87         char                    devpath[32];
88         int                             mode;
89         enum sms_device_type_st type;
90 };
91
92 static struct list_head g_smscore_notifyees;
93 static struct list_head g_smscore_devices;
94 static struct mutex g_smscore_deviceslock;
95
96 static struct list_head g_smscore_registry;
97 static struct mutex g_smscore_registrylock;
98
99 static int default_mode = 4;
100
101 module_param(default_mode, int, 0644);
102 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
103
104 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
105 {
106         struct smscore_registry_entry_t *entry;
107         struct list_head *next;
108
109         kmutex_lock(&g_smscore_registrylock);
110         for (next = g_smscore_registry.next;
111              next != &g_smscore_registry;
112              next = next->next) {
113                 entry = (struct smscore_registry_entry_t *) next;
114                 if (!strcmp(entry->devpath, devpath)) {
115                         kmutex_unlock(&g_smscore_registrylock);
116                         return entry;
117                 }
118         }
119         entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
120         if (entry) {
121                 entry->mode = default_mode;
122                 strcpy(entry->devpath, devpath);
123                 list_add(&entry->entry, &g_smscore_registry);
124         } else
125                 sms_err("failed to create smscore_registry.");
126         kmutex_unlock(&g_smscore_registrylock);
127         return entry;
128 }
129
130 int smscore_registry_getmode(char *devpath)
131 {
132         struct smscore_registry_entry_t *entry;
133
134         entry = smscore_find_registry(devpath);
135         if (entry)
136                 return entry->mode;
137         else
138                 sms_err("No registry found.");
139
140         return default_mode;
141 }
142 EXPORT_SYMBOL_GPL(smscore_registry_getmode);
143
144 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
145 {
146         struct smscore_registry_entry_t *entry;
147
148         entry = smscore_find_registry(devpath);
149         if (entry)
150                 return entry->type;
151         else
152                 sms_err("No registry found.");
153
154         return -1;
155 }
156
157 void smscore_registry_setmode(char *devpath, int mode)
158 {
159         struct smscore_registry_entry_t *entry;
160
161         entry = smscore_find_registry(devpath);
162         if (entry)
163                 entry->mode = mode;
164         else
165                 sms_err("No registry found.");
166 }
167
168 static void smscore_registry_settype(char *devpath,
169                                      enum sms_device_type_st type)
170 {
171         struct smscore_registry_entry_t *entry;
172
173         entry = smscore_find_registry(devpath);
174         if (entry)
175                 entry->type = type;
176         else
177                 sms_err("No registry found.");
178 }
179
180
181 static void list_add_locked(struct list_head *new, struct list_head *head,
182                             spinlock_t *lock)
183 {
184         unsigned long flags;
185
186         spin_lock_irqsave(lock, flags);
187
188         list_add(new, head);
189
190         spin_unlock_irqrestore(lock, flags);
191 }
192
193 /**
194  * register a client callback that called when device plugged in/unplugged
195  * NOTE: if devices exist callback is called immediately for each device
196  *
197  * @param hotplug callback
198  *
199  * @return 0 on success, <0 on error.
200  */
201 int smscore_register_hotplug(hotplug_t hotplug)
202 {
203         struct smscore_device_notifyee_t *notifyee;
204         struct list_head *next, *first;
205         int rc = 0;
206
207         kmutex_lock(&g_smscore_deviceslock);
208
209         notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
210                            GFP_KERNEL);
211         if (notifyee) {
212                 /* now notify callback about existing devices */
213                 first = &g_smscore_devices;
214                 for (next = first->next;
215                      next != first && !rc;
216                      next = next->next) {
217                         struct smscore_device_t *coredev =
218                                 (struct smscore_device_t *) next;
219                         rc = hotplug(coredev, coredev->device, 1);
220                 }
221
222                 if (rc >= 0) {
223                         notifyee->hotplug = hotplug;
224                         list_add(&notifyee->entry, &g_smscore_notifyees);
225                 } else
226                         kfree(notifyee);
227         } else
228                 rc = -ENOMEM;
229
230         kmutex_unlock(&g_smscore_deviceslock);
231
232         return rc;
233 }
234 EXPORT_SYMBOL_GPL(smscore_register_hotplug);
235
236 /**
237  * unregister a client callback that called when device plugged in/unplugged
238  *
239  * @param hotplug callback
240  *
241  */
242 void smscore_unregister_hotplug(hotplug_t hotplug)
243 {
244         struct list_head *next, *first;
245
246         kmutex_lock(&g_smscore_deviceslock);
247
248         first = &g_smscore_notifyees;
249
250         for (next = first->next; next != first;) {
251                 struct smscore_device_notifyee_t *notifyee =
252                         (struct smscore_device_notifyee_t *) next;
253                 next = next->next;
254
255                 if (notifyee->hotplug == hotplug) {
256                         list_del(&notifyee->entry);
257                         kfree(notifyee);
258                 }
259         }
260
261         kmutex_unlock(&g_smscore_deviceslock);
262 }
263 EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
264
265 static void smscore_notify_clients(struct smscore_device_t *coredev)
266 {
267         struct smscore_client_t *client;
268
269         /* the client must call smscore_unregister_client from remove handler */
270         while (!list_empty(&coredev->clients)) {
271                 client = (struct smscore_client_t *) coredev->clients.next;
272                 client->onremove_handler(client->context);
273         }
274 }
275
276 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
277                                     struct device *device, int arrival)
278 {
279         struct smscore_device_notifyee_t *elem;
280         int rc = 0;
281
282         /* note: must be called under g_deviceslock */
283
284         list_for_each_entry(elem, &g_smscore_notifyees, entry) {
285                 rc = elem->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         init_completion(&dev->gpio_configuration_done);
352         init_completion(&dev->gpio_set_level_done);
353         init_completion(&dev->gpio_get_level_done);
354         init_completion(&dev->ir_init_done);
355
356         /* Buffer management */
357         init_waitqueue_head(&dev->buffer_mng_waitq);
358
359         /* alloc common buffer */
360         dev->common_buffer_size = params->buffer_size * params->num_buffers;
361         dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
362                                                 &dev->common_buffer_phys,
363                                                 GFP_KERNEL | GFP_DMA);
364         if (!dev->common_buffer) {
365                 smscore_unregister_device(dev);
366                 return -ENOMEM;
367         }
368
369         /* prepare dma buffers */
370         for (buffer = dev->common_buffer;
371              dev->num_buffers < params->num_buffers;
372              dev->num_buffers++, buffer += params->buffer_size) {
373                 struct smscore_buffer_t *cb =
374                         smscore_createbuffer(buffer, dev->common_buffer,
375                                              dev->common_buffer_phys);
376                 if (!cb) {
377                         smscore_unregister_device(dev);
378                         return -ENOMEM;
379                 }
380
381                 smscore_putbuffer(dev, cb);
382         }
383
384         sms_info("allocated %d buffers", dev->num_buffers);
385
386         dev->mode = DEVICE_MODE_NONE;
387         dev->context = params->context;
388         dev->device = params->device;
389         dev->setmode_handler = params->setmode_handler;
390         dev->detectmode_handler = params->detectmode_handler;
391         dev->sendrequest_handler = params->sendrequest_handler;
392         dev->preload_handler = params->preload_handler;
393         dev->postload_handler = params->postload_handler;
394
395         dev->device_flags = params->flags;
396         strcpy(dev->devpath, params->devpath);
397
398         smscore_registry_settype(dev->devpath, params->device_type);
399
400         /* add device to devices list */
401         kmutex_lock(&g_smscore_deviceslock);
402         list_add(&dev->entry, &g_smscore_devices);
403         kmutex_unlock(&g_smscore_deviceslock);
404
405         *coredev = dev;
406
407         sms_info("device %p created", dev);
408
409         return 0;
410 }
411 EXPORT_SYMBOL_GPL(smscore_register_device);
412
413
414 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
415                 void *buffer, size_t size, struct completion *completion) {
416         int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
417         if (rc < 0) {
418                 sms_info("sendrequest returned error %d", rc);
419                 return rc;
420         }
421
422         return wait_for_completion_timeout(completion,
423                         msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
424                         0 : -ETIME;
425 }
426
427 /**
428  * Starts & enables IR operations
429  *
430  * @return 0 on success, < 0 on error.
431  */
432 static int smscore_init_ir(struct smscore_device_t *coredev)
433 {
434         int ir_io;
435         int rc;
436         void *buffer;
437
438         coredev->ir.dev = NULL;
439         ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
440         if (ir_io) {/* only if IR port exist we use IR sub-module */
441                 sms_info("IR loading");
442                 rc = sms_ir_init(coredev);
443
444                 if      (rc != 0)
445                         sms_err("Error initialization DTV IR sub-module");
446                 else {
447                         buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
448                                                 SMS_DMA_ALIGNMENT,
449                                                 GFP_KERNEL | GFP_DMA);
450                         if (buffer) {
451                                 struct SmsMsgData_ST2 *msg =
452                                 (struct SmsMsgData_ST2 *)
453                                 SMS_ALIGN_ADDRESS(buffer);
454
455                                 SMS_INIT_MSG(&msg->xMsgHeader,
456                                                 MSG_SMS_START_IR_REQ,
457                                                 sizeof(struct SmsMsgData_ST2));
458                                 msg->msgData[0] = coredev->ir.controller;
459                                 msg->msgData[1] = coredev->ir.timeout;
460
461                                 smsendian_handle_tx_message(
462                                         (struct SmsMsgHdr_ST2 *)msg);
463                                 rc = smscore_sendrequest_and_wait(coredev, msg,
464                                                 msg->xMsgHeader. msgLength,
465                                                 &coredev->ir_init_done);
466
467                                 kfree(buffer);
468                         } else
469                                 sms_err
470                                 ("Sending IR initialization message failed");
471                 }
472         } else
473                 sms_info("IR port has not been detected");
474
475         return 0;
476 }
477
478 /**
479  * sets initial device mode and notifies client hotplugs that device is ready
480  *
481  * @param coredev pointer to a coredev object returned by
482  *                smscore_register_device
483  *
484  * @return 0 on success, <0 on error.
485  */
486 int smscore_start_device(struct smscore_device_t *coredev)
487 {
488         int rc = smscore_set_device_mode(
489                         coredev, smscore_registry_getmode(coredev->devpath));
490         if (rc < 0) {
491                 sms_info("set device mode faile , rc %d", rc);
492                 return rc;
493         }
494
495         kmutex_lock(&g_smscore_deviceslock);
496
497         rc = smscore_notify_callbacks(coredev, coredev->device, 1);
498         smscore_init_ir(coredev);
499
500         sms_info("device %p started, rc %d", coredev, rc);
501
502         kmutex_unlock(&g_smscore_deviceslock);
503
504         return rc;
505 }
506 EXPORT_SYMBOL_GPL(smscore_start_device);
507
508
509 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
510                                          void *buffer, size_t size)
511 {
512         struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
513         struct SmsMsgHdr_ST *msg;
514         u32 mem_address;
515         u8 *payload = firmware->Payload;
516         int rc = 0;
517         firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
518         firmware->Length = le32_to_cpu(firmware->Length);
519
520         mem_address = firmware->StartAddress;
521
522         sms_info("loading FW to addr 0x%x size %d",
523                  mem_address, firmware->Length);
524         if (coredev->preload_handler) {
525                 rc = coredev->preload_handler(coredev->context);
526                 if (rc < 0)
527                         return rc;
528         }
529
530         /* PAGE_SIZE buffer shall be enough and dma aligned */
531         msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
532         if (!msg)
533                 return -ENOMEM;
534
535         if (coredev->mode != DEVICE_MODE_NONE) {
536                 sms_debug("sending reload command.");
537                 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
538                              sizeof(struct SmsMsgHdr_ST));
539                 rc = smscore_sendrequest_and_wait(coredev, msg,
540                                                   msg->msgLength,
541                                                   &coredev->reload_start_done);
542                 mem_address = *(u32 *) &payload[20];
543         }
544
545         while (size && rc >= 0) {
546                 struct SmsDataDownload_ST *DataMsg =
547                         (struct SmsDataDownload_ST *) msg;
548                 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
549
550                 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
551                              (u16)(sizeof(struct SmsMsgHdr_ST) +
552                                       sizeof(u32) + payload_size));
553
554                 DataMsg->MemAddr = mem_address;
555                 memcpy(DataMsg->Payload, payload, payload_size);
556
557                 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
558                     (coredev->mode == DEVICE_MODE_NONE))
559                         rc = coredev->sendrequest_handler(
560                                 coredev->context, DataMsg,
561                                 DataMsg->xMsgHeader.msgLength);
562                 else
563                         rc = smscore_sendrequest_and_wait(
564                                 coredev, DataMsg,
565                                 DataMsg->xMsgHeader.msgLength,
566                                 &coredev->data_download_done);
567
568                 payload += payload_size;
569                 size -= payload_size;
570                 mem_address += payload_size;
571         }
572
573         if (rc >= 0) {
574                 if (coredev->mode == DEVICE_MODE_NONE) {
575                         struct SmsMsgData_ST *TriggerMsg =
576                                 (struct SmsMsgData_ST *) msg;
577
578                         SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
579                                      sizeof(struct SmsMsgHdr_ST) +
580                                      sizeof(u32) * 5);
581
582                         TriggerMsg->msgData[0] = firmware->StartAddress;
583                                                 /* Entry point */
584                         TriggerMsg->msgData[1] = 5; /* Priority */
585                         TriggerMsg->msgData[2] = 0x200; /* Stack size */
586                         TriggerMsg->msgData[3] = 0; /* Parameter */
587                         TriggerMsg->msgData[4] = 4; /* Task ID */
588
589                         if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
590                                 rc = coredev->sendrequest_handler(
591                                         coredev->context, TriggerMsg,
592                                         TriggerMsg->xMsgHeader.msgLength);
593                                 msleep(100);
594                         } else
595                                 rc = smscore_sendrequest_and_wait(
596                                         coredev, TriggerMsg,
597                                         TriggerMsg->xMsgHeader.msgLength,
598                                         &coredev->trigger_done);
599                 } else {
600                         SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
601                                      sizeof(struct SmsMsgHdr_ST));
602
603                         rc = coredev->sendrequest_handler(coredev->context,
604                                                           msg, msg->msgLength);
605                 }
606                 msleep(500);
607         }
608
609         sms_debug("rc=%d, postload=%p ", rc,
610                   coredev->postload_handler);
611
612         kfree(msg);
613
614         return ((rc >= 0) && coredev->postload_handler) ?
615                 coredev->postload_handler(coredev->context) :
616                 rc;
617 }
618
619 /**
620  * loads specified firmware into a buffer and calls device loadfirmware_handler
621  *
622  * @param coredev pointer to a coredev object returned by
623  *                smscore_register_device
624  * @param filename null-terminated string specifies firmware file name
625  * @param loadfirmware_handler device handler that loads firmware
626  *
627  * @return 0 on success, <0 on error.
628  */
629 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
630                                            char *filename,
631                                            loadfirmware_t loadfirmware_handler)
632 {
633         int rc = -ENOENT;
634         const struct firmware *fw;
635         u8 *fw_buffer;
636
637         if (loadfirmware_handler == NULL && !(coredev->device_flags &
638                                               SMS_DEVICE_FAMILY2))
639                 return -EINVAL;
640
641         rc = request_firmware(&fw, filename, coredev->device);
642         if (rc < 0) {
643                 sms_info("failed to open \"%s\"", filename);
644                 return rc;
645         }
646         sms_info("read FW %s, size=%zd", filename, fw->size);
647         fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
648                             GFP_KERNEL | GFP_DMA);
649         if (fw_buffer) {
650                 memcpy(fw_buffer, fw->data, fw->size);
651
652                 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
653                       smscore_load_firmware_family2(coredev,
654                                                     fw_buffer,
655                                                     fw->size) :
656                       loadfirmware_handler(coredev->context,
657                                            fw_buffer, fw->size);
658
659                 kfree(fw_buffer);
660         } else {
661                 sms_info("failed to allocate firmware buffer");
662                 rc = -ENOMEM;
663         }
664
665         release_firmware(fw);
666
667         return rc;
668 }
669
670 /**
671  * notifies all clients registered with the device, notifies hotplugs,
672  * frees all buffers and coredev object
673  *
674  * @param coredev pointer to a coredev object returned by
675  *                smscore_register_device
676  *
677  * @return 0 on success, <0 on error.
678  */
679 void smscore_unregister_device(struct smscore_device_t *coredev)
680 {
681         struct smscore_buffer_t *cb;
682         int num_buffers = 0;
683         int retry = 0;
684
685         kmutex_lock(&g_smscore_deviceslock);
686
687         /* Release input device (IR) resources */
688         sms_ir_exit(coredev);
689
690         smscore_notify_clients(coredev);
691         smscore_notify_callbacks(coredev, NULL, 0);
692
693         /* at this point all buffers should be back
694          * onresponse must no longer be called */
695
696         while (1) {
697                 while (!list_empty(&coredev->buffers)) {
698                         cb = (struct smscore_buffer_t *) coredev->buffers.next;
699                         list_del(&cb->entry);
700                         kfree(cb);
701                         num_buffers++;
702                 }
703                 if (num_buffers == coredev->num_buffers)
704                         break;
705                 if (++retry > 10) {
706                         sms_info("exiting although "
707                                  "not all buffers released.");
708                         break;
709                 }
710
711                 sms_info("waiting for %d buffer(s)",
712                          coredev->num_buffers - num_buffers);
713                 msleep(100);
714         }
715
716         sms_info("freed %d buffers", num_buffers);
717
718         if (coredev->common_buffer)
719                 dma_free_coherent(NULL, coredev->common_buffer_size,
720                         coredev->common_buffer, coredev->common_buffer_phys);
721
722         if (coredev->fw_buf != NULL)
723                 kfree(coredev->fw_buf);
724
725         list_del(&coredev->entry);
726         kfree(coredev);
727
728         kmutex_unlock(&g_smscore_deviceslock);
729
730         sms_info("device %p destroyed", coredev);
731 }
732 EXPORT_SYMBOL_GPL(smscore_unregister_device);
733
734 static int smscore_detect_mode(struct smscore_device_t *coredev)
735 {
736         void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
737                                GFP_KERNEL | GFP_DMA);
738         struct SmsMsgHdr_ST *msg =
739                 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
740         int rc;
741
742         if (!buffer)
743                 return -ENOMEM;
744
745         SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
746                      sizeof(struct SmsMsgHdr_ST));
747
748         rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
749                                           &coredev->version_ex_done);
750         if (rc == -ETIME) {
751                 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
752
753                 if (wait_for_completion_timeout(&coredev->resume_done,
754                                                 msecs_to_jiffies(5000))) {
755                         rc = smscore_sendrequest_and_wait(
756                                 coredev, msg, msg->msgLength,
757                                 &coredev->version_ex_done);
758                         if (rc < 0)
759                                 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
760                                         "second try, rc %d", rc);
761                 } else
762                         rc = -ETIME;
763         }
764
765         kfree(buffer);
766
767         return rc;
768 }
769
770 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
771         /*Stellar               NOVA A0         Nova B0         VEGA*/
772         /*DVBT*/
773         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
774         /*DVBH*/
775         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
776         /*TDMB*/
777         {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
778         /*DABIP*/
779         {"none", "none", "none", "none"},
780         /*BDA*/
781         {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
782         /*ISDBT*/
783         {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
784         /*ISDBTBDA*/
785         {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
786         /*CMMB*/
787         {"none", "none", "none", "cmmb_vega_12mhz.inp"}
788 };
789
790 static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
791                                     int mode, enum sms_device_type_st type)
792 {
793         char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
794         return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
795 }
796
797 /**
798  * calls device handler to change mode of operation
799  * NOTE: stellar/usb may disconnect when changing mode
800  *
801  * @param coredev pointer to a coredev object returned by
802  *                smscore_register_device
803  * @param mode requested mode of operation
804  *
805  * @return 0 on success, <0 on error.
806  */
807 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
808 {
809         void *buffer;
810         int rc = 0;
811         enum sms_device_type_st type;
812
813         sms_debug("set device mode to %d", mode);
814         if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
815                 if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
816                         sms_err("invalid mode specified %d", mode);
817                         return -EINVAL;
818                 }
819
820                 smscore_registry_setmode(coredev->devpath, mode);
821
822                 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
823                         rc = smscore_detect_mode(coredev);
824                         if (rc < 0) {
825                                 sms_err("mode detect failed %d", rc);
826                                 return rc;
827                         }
828                 }
829
830                 if (coredev->mode == mode) {
831                         sms_info("device mode %d already set", mode);
832                         return 0;
833                 }
834
835                 if (!(coredev->modes_supported & (1 << mode))) {
836                         char *fw_filename;
837
838                         type = smscore_registry_gettype(coredev->devpath);
839                         fw_filename = sms_get_fw_name(coredev, mode, type);
840
841                         rc = smscore_load_firmware_from_file(coredev,
842                                                              fw_filename, NULL);
843                         if (rc < 0) {
844                                 sms_warn("error %d loading firmware: %s, "
845                                          "trying again with default firmware",
846                                          rc, fw_filename);
847
848                                 /* try again with the default firmware */
849                                 fw_filename = smscore_fw_lkup[mode][type];
850                                 rc = smscore_load_firmware_from_file(coredev,
851                                                              fw_filename, NULL);
852
853                                 if (rc < 0) {
854                                         sms_warn("error %d loading "
855                                                  "firmware: %s", rc,
856                                                  fw_filename);
857                                         return rc;
858                                 }
859                         }
860                         sms_log("firmware download success: %s", fw_filename);
861                 } else
862                         sms_info("mode %d supported by running "
863                                  "firmware", mode);
864
865                 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
866                                  SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
867                 if (buffer) {
868                         struct SmsMsgData_ST *msg =
869                                 (struct SmsMsgData_ST *)
870                                         SMS_ALIGN_ADDRESS(buffer);
871
872                         SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
873                                      sizeof(struct SmsMsgData_ST));
874                         msg->msgData[0] = mode;
875
876                         rc = smscore_sendrequest_and_wait(
877                                 coredev, msg, msg->xMsgHeader.msgLength,
878                                 &coredev->init_device_done);
879
880                         kfree(buffer);
881                 } else {
882                         sms_err("Could not allocate buffer for "
883                                 "init device message.");
884                         rc = -ENOMEM;
885                 }
886         } else {
887                 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
888                         sms_err("invalid mode specified %d", mode);
889                         return -EINVAL;
890                 }
891
892                 smscore_registry_setmode(coredev->devpath, mode);
893
894                 if (coredev->detectmode_handler)
895                         coredev->detectmode_handler(coredev->context,
896                                                     &coredev->mode);
897
898                 if (coredev->mode != mode && coredev->setmode_handler)
899                         rc = coredev->setmode_handler(coredev->context, mode);
900         }
901
902         if (rc >= 0) {
903                 coredev->mode = mode;
904                 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
905         }
906
907         if (rc < 0)
908                 sms_err("return error code %d.", rc);
909         return rc;
910 }
911
912 /**
913  * calls device handler to get current mode of operation
914  *
915  * @param coredev pointer to a coredev object returned by
916  *                smscore_register_device
917  *
918  * @return current mode
919  */
920 int smscore_get_device_mode(struct smscore_device_t *coredev)
921 {
922         return coredev->mode;
923 }
924 EXPORT_SYMBOL_GPL(smscore_get_device_mode);
925
926 /**
927  * find client by response id & type within the clients list.
928  * return client handle or NULL.
929  *
930  * @param coredev pointer to a coredev object returned by
931  *                smscore_register_device
932  * @param data_type client data type (SMS_DONT_CARE for all types)
933  * @param id client id (SMS_DONT_CARE for all id)
934  *
935  */
936 static struct
937 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
938                                       int data_type, int id)
939 {
940         struct list_head *first;
941         struct smscore_client_t *client;
942         unsigned long flags;
943         struct list_head *firstid;
944         struct smscore_idlist_t *client_id;
945
946         spin_lock_irqsave(&coredev->clientslock, flags);
947         first = &coredev->clients;
948         list_for_each_entry(client, first, entry) {
949                 firstid = &client->idlist;
950                 list_for_each_entry(client_id, firstid, entry) {
951                         if ((client_id->id == id) &&
952                             (client_id->data_type == data_type ||
953                             (client_id->data_type == 0)))
954                                 goto found;
955                 }
956         }
957         client = NULL;
958 found:
959         spin_unlock_irqrestore(&coredev->clientslock, flags);
960         return client;
961 }
962
963 /**
964  * find client by response id/type, call clients onresponse handler
965  * return buffer to pool on error
966  *
967  * @param coredev pointer to a coredev object returned by
968  *                smscore_register_device
969  * @param cb pointer to response buffer descriptor
970  *
971  */
972 void smscore_onresponse(struct smscore_device_t *coredev,
973                 struct smscore_buffer_t *cb) {
974         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
975                         + cb->offset);
976         struct smscore_client_t *client;
977         int rc = -EBUSY;
978         static unsigned long last_sample_time; /* = 0; */
979         static int data_total; /* = 0; */
980         unsigned long time_now = jiffies_to_msecs(jiffies);
981
982         if (!last_sample_time)
983                 last_sample_time = time_now;
984
985         if (time_now - last_sample_time > 10000) {
986                 sms_debug("\ndata rate %d bytes/secs",
987                           (int)((data_total * 1000) /
988                                 (time_now - last_sample_time)));
989
990                 last_sample_time = time_now;
991                 data_total = 0;
992         }
993
994         data_total += cb->size;
995         /* Do we need to re-route? */
996         if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
997                         (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
998                 if (coredev->mode == DEVICE_MODE_DVBT_BDA)
999                         phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
1000         }
1001
1002
1003         client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1004
1005         /* If no client registered for type & id,
1006          * check for control client where type is not registered */
1007         if (client)
1008                 rc = client->onresponse_handler(client->context, cb);
1009
1010         if (rc < 0) {
1011                 switch (phdr->msgType) {
1012                 case MSG_SMS_GET_VERSION_EX_RES:
1013                 {
1014                         struct SmsVersionRes_ST *ver =
1015                                 (struct SmsVersionRes_ST *) phdr;
1016                         sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1017                                   "id %d prots 0x%x ver %d.%d",
1018                                   ver->FirmwareId, ver->SupportedProtocols,
1019                                   ver->RomVersionMajor, ver->RomVersionMinor);
1020
1021                         coredev->mode = ver->FirmwareId == 255 ?
1022                                 DEVICE_MODE_NONE : ver->FirmwareId;
1023                         coredev->modes_supported = ver->SupportedProtocols;
1024
1025                         complete(&coredev->version_ex_done);
1026                         break;
1027                 }
1028                 case MSG_SMS_INIT_DEVICE_RES:
1029                         sms_debug("MSG_SMS_INIT_DEVICE_RES");
1030                         complete(&coredev->init_device_done);
1031                         break;
1032                 case MSG_SW_RELOAD_START_RES:
1033                         sms_debug("MSG_SW_RELOAD_START_RES");
1034                         complete(&coredev->reload_start_done);
1035                         break;
1036                 case MSG_SMS_DATA_DOWNLOAD_RES:
1037                         complete(&coredev->data_download_done);
1038                         break;
1039                 case MSG_SW_RELOAD_EXEC_RES:
1040                         sms_debug("MSG_SW_RELOAD_EXEC_RES");
1041                         break;
1042                 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1043                         sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1044                         complete(&coredev->trigger_done);
1045                         break;
1046                 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1047                         complete(&coredev->resume_done);
1048                         break;
1049                 case MSG_SMS_GPIO_CONFIG_EX_RES:
1050                         sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1051                         complete(&coredev->gpio_configuration_done);
1052                         break;
1053                 case MSG_SMS_GPIO_SET_LEVEL_RES:
1054                         sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1055                         complete(&coredev->gpio_set_level_done);
1056                         break;
1057                 case MSG_SMS_GPIO_GET_LEVEL_RES:
1058                 {
1059                         u32 *msgdata = (u32 *) phdr;
1060                         coredev->gpio_get_res = msgdata[1];
1061                         sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1062                                         coredev->gpio_get_res);
1063                         complete(&coredev->gpio_get_level_done);
1064                         break;
1065                 }
1066                 case MSG_SMS_START_IR_RES:
1067                         complete(&coredev->ir_init_done);
1068                         break;
1069                 case MSG_SMS_IR_SAMPLES_IND:
1070                         sms_ir_event(coredev,
1071                                 (const char *)
1072                                 ((char *)phdr
1073                                 + sizeof(struct SmsMsgHdr_ST)),
1074                                 (int)phdr->msgLength
1075                                 - sizeof(struct SmsMsgHdr_ST));
1076                         break;
1077
1078                 default:
1079                         break;
1080                 }
1081                 smscore_putbuffer(coredev, cb);
1082         }
1083 }
1084 EXPORT_SYMBOL_GPL(smscore_onresponse);
1085
1086 /**
1087  * return pointer to next free buffer descriptor from core pool
1088  *
1089  * @param coredev pointer to a coredev object returned by
1090  *                smscore_register_device
1091  *
1092  * @return pointer to descriptor on success, NULL on error.
1093  */
1094
1095 struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
1096 {
1097         struct smscore_buffer_t *cb = NULL;
1098         unsigned long flags;
1099
1100         spin_lock_irqsave(&coredev->bufferslock, flags);
1101         if (!list_empty(&coredev->buffers)) {
1102                 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1103                 list_del(&cb->entry);
1104         }
1105         spin_unlock_irqrestore(&coredev->bufferslock, flags);
1106         return cb;
1107 }
1108
1109 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1110 {
1111         struct smscore_buffer_t *cb = NULL;
1112
1113         wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
1114
1115         return cb;
1116 }
1117 EXPORT_SYMBOL_GPL(smscore_getbuffer);
1118
1119 /**
1120  * return buffer descriptor to a pool
1121  *
1122  * @param coredev pointer to a coredev object returned by
1123  *                smscore_register_device
1124  * @param cb pointer buffer descriptor
1125  *
1126  */
1127 void smscore_putbuffer(struct smscore_device_t *coredev,
1128                 struct smscore_buffer_t *cb) {
1129         wake_up_interruptible(&coredev->buffer_mng_waitq);
1130         list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1131 }
1132 EXPORT_SYMBOL_GPL(smscore_putbuffer);
1133
1134 static int smscore_validate_client(struct smscore_device_t *coredev,
1135                                    struct smscore_client_t *client,
1136                                    int data_type, int id)
1137 {
1138         struct smscore_idlist_t *listentry;
1139         struct smscore_client_t *registered_client;
1140
1141         if (!client) {
1142                 sms_err("bad parameter.");
1143                 return -EINVAL;
1144         }
1145         registered_client = smscore_find_client(coredev, data_type, id);
1146         if (registered_client == client)
1147                 return 0;
1148
1149         if (registered_client) {
1150                 sms_err("The msg ID already registered to another client.");
1151                 return -EEXIST;
1152         }
1153         listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1154         if (!listentry) {
1155                 sms_err("Can't allocate memory for client id.");
1156                 return -ENOMEM;
1157         }
1158         listentry->id = id;
1159         listentry->data_type = data_type;
1160         list_add_locked(&listentry->entry, &client->idlist,
1161                         &coredev->clientslock);
1162         return 0;
1163 }
1164
1165 /**
1166  * creates smsclient object, check that id is taken by another client
1167  *
1168  * @param coredev pointer to a coredev object from clients hotplug
1169  * @param initial_id all messages with this id would be sent to this client
1170  * @param data_type all messages of this type would be sent to this client
1171  * @param onresponse_handler client handler that is called to
1172  *                           process incoming messages
1173  * @param onremove_handler client handler that is called when device is removed
1174  * @param context client-specific context
1175  * @param client pointer to a value that receives created smsclient object
1176  *
1177  * @return 0 on success, <0 on error.
1178  */
1179 int smscore_register_client(struct smscore_device_t *coredev,
1180                             struct smsclient_params_t *params,
1181                             struct smscore_client_t **client)
1182 {
1183         struct smscore_client_t *newclient;
1184         /* check that no other channel with same parameters exists */
1185         if (smscore_find_client(coredev, params->data_type,
1186                                 params->initial_id)) {
1187                 sms_err("Client already exist.");
1188                 return -EEXIST;
1189         }
1190
1191         newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1192         if (!newclient) {
1193                 sms_err("Failed to allocate memory for client.");
1194                 return -ENOMEM;
1195         }
1196
1197         INIT_LIST_HEAD(&newclient->idlist);
1198         newclient->coredev = coredev;
1199         newclient->onresponse_handler = params->onresponse_handler;
1200         newclient->onremove_handler = params->onremove_handler;
1201         newclient->context = params->context;
1202         list_add_locked(&newclient->entry, &coredev->clients,
1203                         &coredev->clientslock);
1204         smscore_validate_client(coredev, newclient, params->data_type,
1205                                 params->initial_id);
1206         *client = newclient;
1207         sms_debug("%p %d %d", params->context, params->data_type,
1208                   params->initial_id);
1209
1210         return 0;
1211 }
1212 EXPORT_SYMBOL_GPL(smscore_register_client);
1213
1214 /**
1215  * frees smsclient object and all subclients associated with it
1216  *
1217  * @param client pointer to smsclient object returned by
1218  *               smscore_register_client
1219  *
1220  */
1221 void smscore_unregister_client(struct smscore_client_t *client)
1222 {
1223         struct smscore_device_t *coredev = client->coredev;
1224         unsigned long flags;
1225
1226         spin_lock_irqsave(&coredev->clientslock, flags);
1227
1228
1229         while (!list_empty(&client->idlist)) {
1230                 struct smscore_idlist_t *identry =
1231                         (struct smscore_idlist_t *) client->idlist.next;
1232                 list_del(&identry->entry);
1233                 kfree(identry);
1234         }
1235
1236         sms_info("%p", client->context);
1237
1238         list_del(&client->entry);
1239         kfree(client);
1240
1241         spin_unlock_irqrestore(&coredev->clientslock, flags);
1242 }
1243 EXPORT_SYMBOL_GPL(smscore_unregister_client);
1244
1245 /**
1246  * verifies that source id is not taken by another client,
1247  * calls device handler to send requests to the device
1248  *
1249  * @param client pointer to smsclient object returned by
1250  *               smscore_register_client
1251  * @param buffer pointer to a request buffer
1252  * @param size size (in bytes) of request buffer
1253  *
1254  * @return 0 on success, <0 on error.
1255  */
1256 int smsclient_sendrequest(struct smscore_client_t *client,
1257                           void *buffer, size_t size)
1258 {
1259         struct smscore_device_t *coredev;
1260         struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1261         int rc;
1262
1263         if (client == NULL) {
1264                 sms_err("Got NULL client");
1265                 return -EINVAL;
1266         }
1267
1268         coredev = client->coredev;
1269
1270         /* check that no other channel with same id exists */
1271         if (coredev == NULL) {
1272                 sms_err("Got NULL coredev");
1273                 return -EINVAL;
1274         }
1275
1276         rc = smscore_validate_client(client->coredev, client, 0,
1277                                      phdr->msgSrcId);
1278         if (rc < 0)
1279                 return rc;
1280
1281         return coredev->sendrequest_handler(coredev->context, buffer, size);
1282 }
1283 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1284
1285
1286 /* old GPIO managements implementation */
1287 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1288                            struct smscore_config_gpio *pinconfig)
1289 {
1290         struct {
1291                 struct SmsMsgHdr_ST hdr;
1292                 u32 data[6];
1293         } msg;
1294
1295         if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1296                 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1297                 msg.hdr.msgDstId = HIF_TASK;
1298                 msg.hdr.msgFlags = 0;
1299                 msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
1300                 msg.hdr.msgLength = sizeof(msg);
1301
1302                 msg.data[0] = pin;
1303                 msg.data[1] = pinconfig->pullupdown;
1304
1305                 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1306                 msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1307
1308                 switch (pinconfig->outputdriving) {
1309                 case SMS_GPIO_OUTPUTDRIVING_16mA:
1310                         msg.data[3] = 7; /* Nova - 16mA */
1311                         break;
1312                 case SMS_GPIO_OUTPUTDRIVING_12mA:
1313                         msg.data[3] = 5; /* Nova - 11mA */
1314                         break;
1315                 case SMS_GPIO_OUTPUTDRIVING_8mA:
1316                         msg.data[3] = 3; /* Nova - 7mA */
1317                         break;
1318                 case SMS_GPIO_OUTPUTDRIVING_4mA:
1319                 default:
1320                         msg.data[3] = 2; /* Nova - 4mA */
1321                         break;
1322                 }
1323
1324                 msg.data[4] = pinconfig->direction;
1325                 msg.data[5] = 0;
1326         } else /* TODO: SMS_DEVICE_FAMILY1 */
1327                 return -EINVAL;
1328
1329         return coredev->sendrequest_handler(coredev->context,
1330                                             &msg, sizeof(msg));
1331 }
1332
1333 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1334 {
1335         struct {
1336                 struct SmsMsgHdr_ST hdr;
1337                 u32 data[3];
1338         } msg;
1339
1340         if (pin > MAX_GPIO_PIN_NUMBER)
1341                 return -EINVAL;
1342
1343         msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1344         msg.hdr.msgDstId = HIF_TASK;
1345         msg.hdr.msgFlags = 0;
1346         msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
1347         msg.hdr.msgLength = sizeof(msg);
1348
1349         msg.data[0] = pin;
1350         msg.data[1] = level ? 1 : 0;
1351         msg.data[2] = 0;
1352
1353         return coredev->sendrequest_handler(coredev->context,
1354                                             &msg, sizeof(msg));
1355 }
1356
1357 /* new GPIO management implementation */
1358 static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1359                 u32 *pGroupNum, u32 *pGroupCfg) {
1360
1361         *pGroupCfg = 1;
1362
1363         if (PinNum <= 1)        {
1364                 *pTranslatedPinNum = 0;
1365                 *pGroupNum = 9;
1366                 *pGroupCfg = 2;
1367         } else if (PinNum >= 2 && PinNum <= 6) {
1368                 *pTranslatedPinNum = 2;
1369                 *pGroupNum = 0;
1370                 *pGroupCfg = 2;
1371         } else if (PinNum >= 7 && PinNum <= 11) {
1372                 *pTranslatedPinNum = 7;
1373                 *pGroupNum = 1;
1374         } else if (PinNum >= 12 && PinNum <= 15) {
1375                 *pTranslatedPinNum = 12;
1376                 *pGroupNum = 2;
1377                 *pGroupCfg = 3;
1378         } else if (PinNum == 16) {
1379                 *pTranslatedPinNum = 16;
1380                 *pGroupNum = 23;
1381         } else if (PinNum >= 17 && PinNum <= 24) {
1382                 *pTranslatedPinNum = 17;
1383                 *pGroupNum = 3;
1384         } else if (PinNum == 25) {
1385                 *pTranslatedPinNum = 25;
1386                 *pGroupNum = 6;
1387         } else if (PinNum >= 26 && PinNum <= 28) {
1388                 *pTranslatedPinNum = 26;
1389                 *pGroupNum = 4;
1390         } else if (PinNum == 29) {
1391                 *pTranslatedPinNum = 29;
1392                 *pGroupNum = 5;
1393                 *pGroupCfg = 2;
1394         } else if (PinNum == 30) {
1395                 *pTranslatedPinNum = 30;
1396                 *pGroupNum = 8;
1397         } else if (PinNum == 31) {
1398                 *pTranslatedPinNum = 31;
1399                 *pGroupNum = 17;
1400         } else
1401                 return -1;
1402
1403         *pGroupCfg <<= 24;
1404
1405         return 0;
1406 }
1407
1408 int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1409                 struct smscore_gpio_config *pGpioConfig) {
1410
1411         u32 totalLen;
1412         u32 TranslatedPinNum = 0;
1413         u32 GroupNum = 0;
1414         u32 ElectricChar;
1415         u32 groupCfg;
1416         void *buffer;
1417         int rc;
1418
1419         struct SetGpioMsg {
1420                 struct SmsMsgHdr_ST xMsgHeader;
1421                 u32 msgData[6];
1422         } *pMsg;
1423
1424
1425         if (PinNum > MAX_GPIO_PIN_NUMBER)
1426                 return -EINVAL;
1427
1428         if (pGpioConfig == NULL)
1429                 return -EINVAL;
1430
1431         totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1432
1433         buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1434                         GFP_KERNEL | GFP_DMA);
1435         if (!buffer)
1436                 return -ENOMEM;
1437
1438         pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1439
1440         pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1441         pMsg->xMsgHeader.msgDstId = HIF_TASK;
1442         pMsg->xMsgHeader.msgFlags = 0;
1443         pMsg->xMsgHeader.msgLength = (u16) totalLen;
1444         pMsg->msgData[0] = PinNum;
1445
1446         if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1447                 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1448                 if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
1449                                 &groupCfg) != 0) {
1450                         rc = -EINVAL;
1451                         goto free;
1452                 }
1453
1454                 pMsg->msgData[1] = TranslatedPinNum;
1455                 pMsg->msgData[2] = GroupNum;
1456                 ElectricChar = (pGpioConfig->PullUpDown)
1457                                 | (pGpioConfig->InputCharacteristics << 2)
1458                                 | (pGpioConfig->OutputSlewRate << 3)
1459                                 | (pGpioConfig->OutputDriving << 4);
1460                 pMsg->msgData[3] = ElectricChar;
1461                 pMsg->msgData[4] = pGpioConfig->Direction;
1462                 pMsg->msgData[5] = groupCfg;
1463         } else {
1464                 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1465                 pMsg->msgData[1] = pGpioConfig->PullUpDown;
1466                 pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
1467                 pMsg->msgData[3] = pGpioConfig->OutputDriving;
1468                 pMsg->msgData[4] = pGpioConfig->Direction;
1469                 pMsg->msgData[5] = 0;
1470         }
1471
1472         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1473         rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1474                         &coredev->gpio_configuration_done);
1475
1476         if (rc != 0) {
1477                 if (rc == -ETIME)
1478                         sms_err("smscore_gpio_configure timeout");
1479                 else
1480                         sms_err("smscore_gpio_configure error");
1481         }
1482 free:
1483         kfree(buffer);
1484
1485         return rc;
1486 }
1487
1488 int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1489                 u8 NewLevel) {
1490
1491         u32 totalLen;
1492         int rc;
1493         void *buffer;
1494
1495         struct SetGpioMsg {
1496                 struct SmsMsgHdr_ST xMsgHeader;
1497                 u32 msgData[3]; /* keep it 3 ! */
1498         } *pMsg;
1499
1500         if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
1501                 return -EINVAL;
1502
1503         totalLen = sizeof(struct SmsMsgHdr_ST) +
1504                         (3 * sizeof(u32)); /* keep it 3 ! */
1505
1506         buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1507                         GFP_KERNEL | GFP_DMA);
1508         if (!buffer)
1509                 return -ENOMEM;
1510
1511         pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1512
1513         pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1514         pMsg->xMsgHeader.msgDstId = HIF_TASK;
1515         pMsg->xMsgHeader.msgFlags = 0;
1516         pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1517         pMsg->xMsgHeader.msgLength = (u16) totalLen;
1518         pMsg->msgData[0] = PinNum;
1519         pMsg->msgData[1] = NewLevel;
1520
1521         /* Send message to SMS */
1522         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1523         rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1524                         &coredev->gpio_set_level_done);
1525
1526         if (rc != 0) {
1527                 if (rc == -ETIME)
1528                         sms_err("smscore_gpio_set_level timeout");
1529                 else
1530                         sms_err("smscore_gpio_set_level error");
1531         }
1532         kfree(buffer);
1533
1534         return rc;
1535 }
1536
1537 int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1538                 u8 *level) {
1539
1540         u32 totalLen;
1541         int rc;
1542         void *buffer;
1543
1544         struct SetGpioMsg {
1545                 struct SmsMsgHdr_ST xMsgHeader;
1546                 u32 msgData[2];
1547         } *pMsg;
1548
1549
1550         if (PinNum > MAX_GPIO_PIN_NUMBER)
1551                 return -EINVAL;
1552
1553         totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1554
1555         buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1556                         GFP_KERNEL | GFP_DMA);
1557         if (!buffer)
1558                 return -ENOMEM;
1559
1560         pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1561
1562         pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1563         pMsg->xMsgHeader.msgDstId = HIF_TASK;
1564         pMsg->xMsgHeader.msgFlags = 0;
1565         pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
1566         pMsg->xMsgHeader.msgLength = (u16) totalLen;
1567         pMsg->msgData[0] = PinNum;
1568         pMsg->msgData[1] = 0;
1569
1570         /* Send message to SMS */
1571         smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1572         rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1573                         &coredev->gpio_get_level_done);
1574
1575         if (rc != 0) {
1576                 if (rc == -ETIME)
1577                         sms_err("smscore_gpio_get_level timeout");
1578                 else
1579                         sms_err("smscore_gpio_get_level error");
1580         }
1581         kfree(buffer);
1582
1583         /* Its a race between other gpio_get_level() and the copy of the single
1584          * global 'coredev->gpio_get_res' to  the function's variable 'level'
1585          */
1586         *level = coredev->gpio_get_res;
1587
1588         return rc;
1589 }
1590
1591 static int __init smscore_module_init(void)
1592 {
1593         int rc = 0;
1594
1595         INIT_LIST_HEAD(&g_smscore_notifyees);
1596         INIT_LIST_HEAD(&g_smscore_devices);
1597         kmutex_init(&g_smscore_deviceslock);
1598
1599         INIT_LIST_HEAD(&g_smscore_registry);
1600         kmutex_init(&g_smscore_registrylock);
1601
1602         return rc;
1603 }
1604
1605 static void __exit smscore_module_exit(void)
1606 {
1607         kmutex_lock(&g_smscore_deviceslock);
1608         while (!list_empty(&g_smscore_notifyees)) {
1609                 struct smscore_device_notifyee_t *notifyee =
1610                         (struct smscore_device_notifyee_t *)
1611                                 g_smscore_notifyees.next;
1612
1613                 list_del(&notifyee->entry);
1614                 kfree(notifyee);
1615         }
1616         kmutex_unlock(&g_smscore_deviceslock);
1617
1618         kmutex_lock(&g_smscore_registrylock);
1619         while (!list_empty(&g_smscore_registry)) {
1620                 struct smscore_registry_entry_t *entry =
1621                         (struct smscore_registry_entry_t *)
1622                                 g_smscore_registry.next;
1623
1624                 list_del(&entry->entry);
1625                 kfree(entry);
1626         }
1627         kmutex_unlock(&g_smscore_registrylock);
1628
1629         sms_debug("");
1630 }
1631
1632 module_init(smscore_module_init);
1633 module_exit(smscore_module_exit);
1634
1635 MODULE_DESCRIPTION("Siano MDTV Core module");
1636 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1637 MODULE_LICENSE("GPL");