2 * Siano core API module
4 * This file contains implementation for the interface to sms core component
8 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
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;
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
17 * See the GNU General Public License for more details.
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.
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>
31 #include <linux/slab.h>
33 #include <linux/firmware.h>
34 #include <linux/wait.h>
35 #include <asm/byteorder.h>
37 #include "smscoreapi.h"
38 #include "sms-cards.h"
40 #include "smsendian.h"
43 module_param_named(debug, sms_dbg, int, 0644);
44 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
46 struct smscore_device_notifyee_t {
47 struct list_head entry;
51 struct smscore_idlist_t {
52 struct list_head entry;
57 struct smscore_client_t {
58 struct list_head entry;
59 struct smscore_device_t *coredev;
61 struct list_head idlist;
62 onresponse_t onresponse_handler;
63 onremove_t onremove_handler;
66 void smscore_set_board_id(struct smscore_device_t *core, int id)
71 int smscore_led_state(struct smscore_device_t *core, int led)
74 core->led_state = led;
75 return core->led_state;
77 EXPORT_SYMBOL_GPL(smscore_set_board_id);
79 int smscore_get_board_id(struct smscore_device_t *core)
81 return core->board_id;
83 EXPORT_SYMBOL_GPL(smscore_get_board_id);
85 struct smscore_registry_entry_t {
86 struct list_head entry;
89 enum sms_device_type_st type;
92 static struct list_head g_smscore_notifyees;
93 static struct list_head g_smscore_devices;
94 static struct mutex g_smscore_deviceslock;
96 static struct list_head g_smscore_registry;
97 static struct mutex g_smscore_registrylock;
99 static int default_mode = 4;
101 module_param(default_mode, int, 0644);
102 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
104 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
106 struct smscore_registry_entry_t *entry;
107 struct list_head *next;
109 kmutex_lock(&g_smscore_registrylock);
110 for (next = g_smscore_registry.next;
111 next != &g_smscore_registry;
113 entry = (struct smscore_registry_entry_t *) next;
114 if (!strcmp(entry->devpath, devpath)) {
115 kmutex_unlock(&g_smscore_registrylock);
119 entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
121 entry->mode = default_mode;
122 strcpy(entry->devpath, devpath);
123 list_add(&entry->entry, &g_smscore_registry);
125 sms_err("failed to create smscore_registry.");
126 kmutex_unlock(&g_smscore_registrylock);
130 int smscore_registry_getmode(char *devpath)
132 struct smscore_registry_entry_t *entry;
134 entry = smscore_find_registry(devpath);
138 sms_err("No registry found.");
142 EXPORT_SYMBOL_GPL(smscore_registry_getmode);
144 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
146 struct smscore_registry_entry_t *entry;
148 entry = smscore_find_registry(devpath);
152 sms_err("No registry found.");
157 void smscore_registry_setmode(char *devpath, int mode)
159 struct smscore_registry_entry_t *entry;
161 entry = smscore_find_registry(devpath);
165 sms_err("No registry found.");
168 static void smscore_registry_settype(char *devpath,
169 enum sms_device_type_st type)
171 struct smscore_registry_entry_t *entry;
173 entry = smscore_find_registry(devpath);
177 sms_err("No registry found.");
181 static void list_add_locked(struct list_head *new, struct list_head *head,
186 spin_lock_irqsave(lock, flags);
190 spin_unlock_irqrestore(lock, flags);
194 * register a client callback that called when device plugged in/unplugged
195 * NOTE: if devices exist callback is called immediately for each device
197 * @param hotplug callback
199 * @return 0 on success, <0 on error.
201 int smscore_register_hotplug(hotplug_t hotplug)
203 struct smscore_device_notifyee_t *notifyee;
204 struct list_head *next, *first;
207 kmutex_lock(&g_smscore_deviceslock);
209 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
212 /* now notify callback about existing devices */
213 first = &g_smscore_devices;
214 for (next = first->next;
215 next != first && !rc;
217 struct smscore_device_t *coredev =
218 (struct smscore_device_t *) next;
219 rc = hotplug(coredev, coredev->device, 1);
223 notifyee->hotplug = hotplug;
224 list_add(¬ifyee->entry, &g_smscore_notifyees);
230 kmutex_unlock(&g_smscore_deviceslock);
234 EXPORT_SYMBOL_GPL(smscore_register_hotplug);
237 * unregister a client callback that called when device plugged in/unplugged
239 * @param hotplug callback
242 void smscore_unregister_hotplug(hotplug_t hotplug)
244 struct list_head *next, *first;
246 kmutex_lock(&g_smscore_deviceslock);
248 first = &g_smscore_notifyees;
250 for (next = first->next; next != first;) {
251 struct smscore_device_notifyee_t *notifyee =
252 (struct smscore_device_notifyee_t *) next;
255 if (notifyee->hotplug == hotplug) {
256 list_del(¬ifyee->entry);
261 kmutex_unlock(&g_smscore_deviceslock);
263 EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
265 static void smscore_notify_clients(struct smscore_device_t *coredev)
267 struct smscore_client_t *client;
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);
276 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
277 struct device *device, int arrival)
279 struct smscore_device_notifyee_t *elem;
282 /* note: must be called under g_deviceslock */
284 list_for_each_entry(elem, &g_smscore_notifyees, entry) {
285 rc = elem->hotplug(coredev, device, arrival);
294 smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
295 dma_addr_t common_buffer_phys)
297 struct smscore_buffer_t *cb =
298 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
300 sms_info("kmalloc(...) failed");
305 cb->offset_in_common = buffer - (u8 *) common_buffer;
306 cb->phys = common_buffer_phys + cb->offset_in_common;
312 * creates coredev object for a device, prepares buffers,
313 * creates buffer mappings, notifies registered hotplugs about new device.
315 * @param params device pointer to struct with device specific parameters
317 * @param coredev pointer to a value that receives created coredev object
319 * @return 0 on success, <0 on error.
321 int smscore_register_device(struct smsdevice_params_t *params,
322 struct smscore_device_t **coredev)
324 struct smscore_device_t *dev;
327 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
329 sms_info("kzalloc(...) failed");
333 /* init list entry so it could be safe in smscore_unregister_device */
334 INIT_LIST_HEAD(&dev->entry);
337 INIT_LIST_HEAD(&dev->clients);
338 INIT_LIST_HEAD(&dev->buffers);
341 spin_lock_init(&dev->clientslock);
342 spin_lock_init(&dev->bufferslock);
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);
356 /* Buffer management */
357 init_waitqueue_head(&dev->buffer_mng_waitq);
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);
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);
377 smscore_unregister_device(dev);
381 smscore_putbuffer(dev, cb);
384 sms_info("allocated %d buffers", dev->num_buffers);
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;
395 dev->device_flags = params->flags;
396 strcpy(dev->devpath, params->devpath);
398 smscore_registry_settype(dev->devpath, params->device_type);
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);
407 sms_info("device %p created", dev);
411 EXPORT_SYMBOL_GPL(smscore_register_device);
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);
418 sms_info("sendrequest returned error %d", rc);
422 return wait_for_completion_timeout(completion,
423 msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
428 * Starts & enables IR operations
430 * @return 0 on success, < 0 on error.
432 static int smscore_init_ir(struct smscore_device_t *coredev)
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);
445 sms_err("Error initialization DTV IR sub-module");
447 buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
449 GFP_KERNEL | GFP_DMA);
451 struct SmsMsgData_ST2 *msg =
452 (struct SmsMsgData_ST2 *)
453 SMS_ALIGN_ADDRESS(buffer);
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;
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);
470 ("Sending IR initialization message failed");
473 sms_info("IR port has not been detected");
479 * sets initial device mode and notifies client hotplugs that device is ready
481 * @param coredev pointer to a coredev object returned by
482 * smscore_register_device
484 * @return 0 on success, <0 on error.
486 int smscore_start_device(struct smscore_device_t *coredev)
488 int rc = smscore_set_device_mode(
489 coredev, smscore_registry_getmode(coredev->devpath));
491 sms_info("set device mode faile , rc %d", rc);
495 kmutex_lock(&g_smscore_deviceslock);
497 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
498 smscore_init_ir(coredev);
500 sms_info("device %p started, rc %d", coredev, rc);
502 kmutex_unlock(&g_smscore_deviceslock);
506 EXPORT_SYMBOL_GPL(smscore_start_device);
509 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
510 void *buffer, size_t size)
512 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
513 struct SmsMsgHdr_ST *msg;
515 u8 *payload = firmware->Payload;
517 firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
518 firmware->Length = le32_to_cpu(firmware->Length);
520 mem_address = firmware->StartAddress;
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);
530 /* PAGE_SIZE buffer shall be enough and dma aligned */
531 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
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,
541 &coredev->reload_start_done);
542 mem_address = *(u32 *) &payload[20];
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);
550 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
551 (u16)(sizeof(struct SmsMsgHdr_ST) +
552 sizeof(u32) + payload_size));
554 DataMsg->MemAddr = mem_address;
555 memcpy(DataMsg->Payload, payload, payload_size);
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);
563 rc = smscore_sendrequest_and_wait(
565 DataMsg->xMsgHeader.msgLength,
566 &coredev->data_download_done);
568 payload += payload_size;
569 size -= payload_size;
570 mem_address += payload_size;
574 if (coredev->mode == DEVICE_MODE_NONE) {
575 struct SmsMsgData_ST *TriggerMsg =
576 (struct SmsMsgData_ST *) msg;
578 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
579 sizeof(struct SmsMsgHdr_ST) +
582 TriggerMsg->msgData[0] = firmware->StartAddress;
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 */
589 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
590 rc = coredev->sendrequest_handler(
591 coredev->context, TriggerMsg,
592 TriggerMsg->xMsgHeader.msgLength);
595 rc = smscore_sendrequest_and_wait(
597 TriggerMsg->xMsgHeader.msgLength,
598 &coredev->trigger_done);
600 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
601 sizeof(struct SmsMsgHdr_ST));
603 rc = coredev->sendrequest_handler(coredev->context,
604 msg, msg->msgLength);
609 sms_debug("rc=%d, postload=%p ", rc,
610 coredev->postload_handler);
614 return ((rc >= 0) && coredev->postload_handler) ?
615 coredev->postload_handler(coredev->context) :
620 * loads specified firmware into a buffer and calls device loadfirmware_handler
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
627 * @return 0 on success, <0 on error.
629 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
631 loadfirmware_t loadfirmware_handler)
634 const struct firmware *fw;
637 if (loadfirmware_handler == NULL && !(coredev->device_flags &
641 rc = request_firmware(&fw, filename, coredev->device);
643 sms_info("failed to open \"%s\"", filename);
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);
650 memcpy(fw_buffer, fw->data, fw->size);
652 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
653 smscore_load_firmware_family2(coredev,
656 loadfirmware_handler(coredev->context,
657 fw_buffer, fw->size);
661 sms_info("failed to allocate firmware buffer");
665 release_firmware(fw);
671 * notifies all clients registered with the device, notifies hotplugs,
672 * frees all buffers and coredev object
674 * @param coredev pointer to a coredev object returned by
675 * smscore_register_device
677 * @return 0 on success, <0 on error.
679 void smscore_unregister_device(struct smscore_device_t *coredev)
681 struct smscore_buffer_t *cb;
685 kmutex_lock(&g_smscore_deviceslock);
687 /* Release input device (IR) resources */
688 sms_ir_exit(coredev);
690 smscore_notify_clients(coredev);
691 smscore_notify_callbacks(coredev, NULL, 0);
693 /* at this point all buffers should be back
694 * onresponse must no longer be called */
697 while (!list_empty(&coredev->buffers)) {
698 cb = (struct smscore_buffer_t *) coredev->buffers.next;
699 list_del(&cb->entry);
703 if (num_buffers == coredev->num_buffers)
706 sms_info("exiting although "
707 "not all buffers released.");
711 sms_info("waiting for %d buffer(s)",
712 coredev->num_buffers - num_buffers);
716 sms_info("freed %d buffers", num_buffers);
718 if (coredev->common_buffer)
719 dma_free_coherent(NULL, coredev->common_buffer_size,
720 coredev->common_buffer, coredev->common_buffer_phys);
722 if (coredev->fw_buf != NULL)
723 kfree(coredev->fw_buf);
725 list_del(&coredev->entry);
728 kmutex_unlock(&g_smscore_deviceslock);
730 sms_info("device %p destroyed", coredev);
732 EXPORT_SYMBOL_GPL(smscore_unregister_device);
734 static int smscore_detect_mode(struct smscore_device_t *coredev)
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);
745 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
746 sizeof(struct SmsMsgHdr_ST));
748 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
749 &coredev->version_ex_done);
751 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
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);
759 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
760 "second try, rc %d", rc);
770 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
771 /*Stellar NOVA A0 Nova B0 VEGA*/
773 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
775 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
777 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
779 {"none", "none", "none", "none"},
781 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
783 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
785 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
787 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
790 static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
791 int mode, enum sms_device_type_st type)
793 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
794 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
798 * calls device handler to change mode of operation
799 * NOTE: stellar/usb may disconnect when changing mode
801 * @param coredev pointer to a coredev object returned by
802 * smscore_register_device
803 * @param mode requested mode of operation
805 * @return 0 on success, <0 on error.
807 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
811 enum sms_device_type_st type;
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);
820 smscore_registry_setmode(coredev->devpath, mode);
822 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
823 rc = smscore_detect_mode(coredev);
825 sms_err("mode detect failed %d", rc);
830 if (coredev->mode == mode) {
831 sms_info("device mode %d already set", mode);
835 if (!(coredev->modes_supported & (1 << mode))) {
838 type = smscore_registry_gettype(coredev->devpath);
839 fw_filename = sms_get_fw_name(coredev, mode, type);
841 rc = smscore_load_firmware_from_file(coredev,
844 sms_warn("error %d loading firmware: %s, "
845 "trying again with default firmware",
848 /* try again with the default firmware */
849 fw_filename = smscore_fw_lkup[mode][type];
850 rc = smscore_load_firmware_from_file(coredev,
854 sms_warn("error %d loading "
860 sms_log("firmware download success: %s", fw_filename);
862 sms_info("mode %d supported by running "
865 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
866 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
868 struct SmsMsgData_ST *msg =
869 (struct SmsMsgData_ST *)
870 SMS_ALIGN_ADDRESS(buffer);
872 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
873 sizeof(struct SmsMsgData_ST));
874 msg->msgData[0] = mode;
876 rc = smscore_sendrequest_and_wait(
877 coredev, msg, msg->xMsgHeader.msgLength,
878 &coredev->init_device_done);
882 sms_err("Could not allocate buffer for "
883 "init device message.");
887 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
888 sms_err("invalid mode specified %d", mode);
892 smscore_registry_setmode(coredev->devpath, mode);
894 if (coredev->detectmode_handler)
895 coredev->detectmode_handler(coredev->context,
898 if (coredev->mode != mode && coredev->setmode_handler)
899 rc = coredev->setmode_handler(coredev->context, mode);
903 coredev->mode = mode;
904 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
908 sms_err("return error code %d.", rc);
913 * calls device handler to get current mode of operation
915 * @param coredev pointer to a coredev object returned by
916 * smscore_register_device
918 * @return current mode
920 int smscore_get_device_mode(struct smscore_device_t *coredev)
922 return coredev->mode;
924 EXPORT_SYMBOL_GPL(smscore_get_device_mode);
927 * find client by response id & type within the clients list.
928 * return client handle or NULL.
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)
937 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
938 int data_type, int id)
940 struct list_head *first;
941 struct smscore_client_t *client;
943 struct list_head *firstid;
944 struct smscore_idlist_t *client_id;
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)))
959 spin_unlock_irqrestore(&coredev->clientslock, flags);
964 * find client by response id/type, call clients onresponse handler
965 * return buffer to pool on error
967 * @param coredev pointer to a coredev object returned by
968 * smscore_register_device
969 * @param cb pointer to response buffer descriptor
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
976 struct smscore_client_t *client;
978 static unsigned long last_sample_time; /* = 0; */
979 static int data_total; /* = 0; */
980 unsigned long time_now = jiffies_to_msecs(jiffies);
982 if (!last_sample_time)
983 last_sample_time = time_now;
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)));
990 last_sample_time = time_now;
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;
1003 client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1005 /* If no client registered for type & id,
1006 * check for control client where type is not registered */
1008 rc = client->onresponse_handler(client->context, cb);
1011 switch (phdr->msgType) {
1012 case MSG_SMS_GET_VERSION_EX_RES:
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);
1021 coredev->mode = ver->FirmwareId == 255 ?
1022 DEVICE_MODE_NONE : ver->FirmwareId;
1023 coredev->modes_supported = ver->SupportedProtocols;
1025 complete(&coredev->version_ex_done);
1028 case MSG_SMS_INIT_DEVICE_RES:
1029 sms_debug("MSG_SMS_INIT_DEVICE_RES");
1030 complete(&coredev->init_device_done);
1032 case MSG_SW_RELOAD_START_RES:
1033 sms_debug("MSG_SW_RELOAD_START_RES");
1034 complete(&coredev->reload_start_done);
1036 case MSG_SMS_DATA_DOWNLOAD_RES:
1037 complete(&coredev->data_download_done);
1039 case MSG_SW_RELOAD_EXEC_RES:
1040 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1042 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1043 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1044 complete(&coredev->trigger_done);
1046 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1047 complete(&coredev->resume_done);
1049 case MSG_SMS_GPIO_CONFIG_EX_RES:
1050 sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1051 complete(&coredev->gpio_configuration_done);
1053 case MSG_SMS_GPIO_SET_LEVEL_RES:
1054 sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1055 complete(&coredev->gpio_set_level_done);
1057 case MSG_SMS_GPIO_GET_LEVEL_RES:
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);
1066 case MSG_SMS_START_IR_RES:
1067 complete(&coredev->ir_init_done);
1069 case MSG_SMS_IR_SAMPLES_IND:
1070 sms_ir_event(coredev,
1073 + sizeof(struct SmsMsgHdr_ST)),
1074 (int)phdr->msgLength
1075 - sizeof(struct SmsMsgHdr_ST));
1081 smscore_putbuffer(coredev, cb);
1084 EXPORT_SYMBOL_GPL(smscore_onresponse);
1087 * return pointer to next free buffer descriptor from core pool
1089 * @param coredev pointer to a coredev object returned by
1090 * smscore_register_device
1092 * @return pointer to descriptor on success, NULL on error.
1095 struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
1097 struct smscore_buffer_t *cb = NULL;
1098 unsigned long flags;
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);
1105 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1109 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1111 struct smscore_buffer_t *cb = NULL;
1113 wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
1117 EXPORT_SYMBOL_GPL(smscore_getbuffer);
1120 * return buffer descriptor to a pool
1122 * @param coredev pointer to a coredev object returned by
1123 * smscore_register_device
1124 * @param cb pointer buffer descriptor
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);
1132 EXPORT_SYMBOL_GPL(smscore_putbuffer);
1134 static int smscore_validate_client(struct smscore_device_t *coredev,
1135 struct smscore_client_t *client,
1136 int data_type, int id)
1138 struct smscore_idlist_t *listentry;
1139 struct smscore_client_t *registered_client;
1142 sms_err("bad parameter.");
1145 registered_client = smscore_find_client(coredev, data_type, id);
1146 if (registered_client == client)
1149 if (registered_client) {
1150 sms_err("The msg ID already registered to another client.");
1153 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1155 sms_err("Can't allocate memory for client id.");
1159 listentry->data_type = data_type;
1160 list_add_locked(&listentry->entry, &client->idlist,
1161 &coredev->clientslock);
1166 * creates smsclient object, check that id is taken by another client
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
1177 * @return 0 on success, <0 on error.
1179 int smscore_register_client(struct smscore_device_t *coredev,
1180 struct smsclient_params_t *params,
1181 struct smscore_client_t **client)
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.");
1191 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1193 sms_err("Failed to allocate memory for client.");
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);
1212 EXPORT_SYMBOL_GPL(smscore_register_client);
1215 * frees smsclient object and all subclients associated with it
1217 * @param client pointer to smsclient object returned by
1218 * smscore_register_client
1221 void smscore_unregister_client(struct smscore_client_t *client)
1223 struct smscore_device_t *coredev = client->coredev;
1224 unsigned long flags;
1226 spin_lock_irqsave(&coredev->clientslock, flags);
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);
1236 sms_info("%p", client->context);
1238 list_del(&client->entry);
1241 spin_unlock_irqrestore(&coredev->clientslock, flags);
1243 EXPORT_SYMBOL_GPL(smscore_unregister_client);
1246 * verifies that source id is not taken by another client,
1247 * calls device handler to send requests to the device
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
1254 * @return 0 on success, <0 on error.
1256 int smsclient_sendrequest(struct smscore_client_t *client,
1257 void *buffer, size_t size)
1259 struct smscore_device_t *coredev;
1260 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1263 if (client == NULL) {
1264 sms_err("Got NULL client");
1268 coredev = client->coredev;
1270 /* check that no other channel with same id exists */
1271 if (coredev == NULL) {
1272 sms_err("Got NULL coredev");
1276 rc = smscore_validate_client(client->coredev, client, 0,
1281 return coredev->sendrequest_handler(coredev->context, buffer, size);
1283 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1286 /* old GPIO managements implementation */
1287 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1288 struct smscore_config_gpio *pinconfig)
1291 struct SmsMsgHdr_ST hdr;
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);
1303 msg.data[1] = pinconfig->pullupdown;
1305 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1306 msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1308 switch (pinconfig->outputdriving) {
1309 case SMS_GPIO_OUTPUTDRIVING_16mA:
1310 msg.data[3] = 7; /* Nova - 16mA */
1312 case SMS_GPIO_OUTPUTDRIVING_12mA:
1313 msg.data[3] = 5; /* Nova - 11mA */
1315 case SMS_GPIO_OUTPUTDRIVING_8mA:
1316 msg.data[3] = 3; /* Nova - 7mA */
1318 case SMS_GPIO_OUTPUTDRIVING_4mA:
1320 msg.data[3] = 2; /* Nova - 4mA */
1324 msg.data[4] = pinconfig->direction;
1326 } else /* TODO: SMS_DEVICE_FAMILY1 */
1329 return coredev->sendrequest_handler(coredev->context,
1333 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1336 struct SmsMsgHdr_ST hdr;
1340 if (pin > MAX_GPIO_PIN_NUMBER)
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);
1350 msg.data[1] = level ? 1 : 0;
1353 return coredev->sendrequest_handler(coredev->context,
1357 /* new GPIO management implementation */
1358 static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1359 u32 *pGroupNum, u32 *pGroupCfg) {
1364 *pTranslatedPinNum = 0;
1367 } else if (PinNum >= 2 && PinNum <= 6) {
1368 *pTranslatedPinNum = 2;
1371 } else if (PinNum >= 7 && PinNum <= 11) {
1372 *pTranslatedPinNum = 7;
1374 } else if (PinNum >= 12 && PinNum <= 15) {
1375 *pTranslatedPinNum = 12;
1378 } else if (PinNum == 16) {
1379 *pTranslatedPinNum = 16;
1381 } else if (PinNum >= 17 && PinNum <= 24) {
1382 *pTranslatedPinNum = 17;
1384 } else if (PinNum == 25) {
1385 *pTranslatedPinNum = 25;
1387 } else if (PinNum >= 26 && PinNum <= 28) {
1388 *pTranslatedPinNum = 26;
1390 } else if (PinNum == 29) {
1391 *pTranslatedPinNum = 29;
1394 } else if (PinNum == 30) {
1395 *pTranslatedPinNum = 30;
1397 } else if (PinNum == 31) {
1398 *pTranslatedPinNum = 31;
1408 int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1409 struct smscore_gpio_config *pGpioConfig) {
1412 u32 TranslatedPinNum = 0;
1420 struct SmsMsgHdr_ST xMsgHeader;
1425 if (PinNum > MAX_GPIO_PIN_NUMBER)
1428 if (pGpioConfig == NULL)
1431 totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1433 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1434 GFP_KERNEL | GFP_DMA);
1438 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
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;
1446 if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1447 pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1448 if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
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;
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;
1472 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1473 rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1474 &coredev->gpio_configuration_done);
1478 sms_err("smscore_gpio_configure timeout");
1480 sms_err("smscore_gpio_configure error");
1488 int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1496 struct SmsMsgHdr_ST xMsgHeader;
1497 u32 msgData[3]; /* keep it 3 ! */
1500 if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
1503 totalLen = sizeof(struct SmsMsgHdr_ST) +
1504 (3 * sizeof(u32)); /* keep it 3 ! */
1506 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1507 GFP_KERNEL | GFP_DMA);
1511 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
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;
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);
1528 sms_err("smscore_gpio_set_level timeout");
1530 sms_err("smscore_gpio_set_level error");
1537 int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1545 struct SmsMsgHdr_ST xMsgHeader;
1550 if (PinNum > MAX_GPIO_PIN_NUMBER)
1553 totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1555 buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1556 GFP_KERNEL | GFP_DMA);
1560 pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
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;
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);
1577 sms_err("smscore_gpio_get_level timeout");
1579 sms_err("smscore_gpio_get_level error");
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'
1586 *level = coredev->gpio_get_res;
1591 static int __init smscore_module_init(void)
1595 INIT_LIST_HEAD(&g_smscore_notifyees);
1596 INIT_LIST_HEAD(&g_smscore_devices);
1597 kmutex_init(&g_smscore_deviceslock);
1599 INIT_LIST_HEAD(&g_smscore_registry);
1600 kmutex_init(&g_smscore_registrylock);
1605 static void __exit smscore_module_exit(void)
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;
1613 list_del(¬ifyee->entry);
1616 kmutex_unlock(&g_smscore_deviceslock);
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;
1624 list_del(&entry->entry);
1627 kmutex_unlock(&g_smscore_registrylock);
1632 module_init(smscore_module_init);
1633 module_exit(smscore_module_exit);
1635 MODULE_DESCRIPTION("Siano MDTV Core module");
1636 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1637 MODULE_LICENSE("GPL");