2 * Siano core API module
4 * This file contains implementation for the interface to sms core component
6 * author: Anatoly Greenblat
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>
32 #include <linux/firmware.h>
34 #include "smscoreapi.h"
35 #include "sms-cards.h"
38 module_param_named(debug, sms_debug, int, 0644);
39 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
41 struct smscore_device_notifyee_t {
42 struct list_head entry;
46 struct smscore_idlist_t {
47 struct list_head entry;
52 struct smscore_client_t {
53 struct list_head entry;
54 struct smscore_device_t *coredev;
56 struct list_head idlist;
57 onresponse_t onresponse_handler;
58 onremove_t onremove_handler;
61 struct smscore_device_t {
62 struct list_head entry;
64 struct list_head clients;
65 struct list_head subclients;
66 spinlock_t clientslock;
68 struct list_head buffers;
69 spinlock_t bufferslock;
73 int common_buffer_size;
74 dma_addr_t common_buffer_phys;
77 struct device *device;
80 unsigned long device_flags;
82 setmode_t setmode_handler;
83 detectmode_t detectmode_handler;
84 sendrequest_t sendrequest_handler;
85 preload_t preload_handler;
86 postload_t postload_handler;
88 int mode, modes_supported;
90 struct completion version_ex_done, data_download_done, trigger_done;
91 struct completion init_device_done, reload_start_done, resume_done;
97 void smscore_set_board_id(struct smscore_device_t *core, int id)
102 int smscore_led_state(struct smscore_device_t *core, int led)
105 core->led_state = led;
106 return core->led_state;
109 int smscore_get_board_id(struct smscore_device_t *core)
111 return core->board_id;
114 struct smscore_registry_entry_t {
115 struct list_head entry;
118 enum sms_device_type_st type;
121 static struct list_head g_smscore_notifyees;
122 static struct list_head g_smscore_devices;
123 static struct mutex g_smscore_deviceslock;
125 static struct list_head g_smscore_registry;
126 static struct mutex g_smscore_registrylock;
128 static int default_mode = 4;
130 module_param(default_mode, int, 0644);
131 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
133 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
135 struct smscore_registry_entry_t *entry;
136 struct list_head *next;
138 kmutex_lock(&g_smscore_registrylock);
139 for (next = g_smscore_registry.next;
140 next != &g_smscore_registry;
142 entry = (struct smscore_registry_entry_t *) next;
143 if (!strcmp(entry->devpath, devpath)) {
144 kmutex_unlock(&g_smscore_registrylock);
148 entry = (struct smscore_registry_entry_t *)
149 kmalloc(sizeof(struct smscore_registry_entry_t),
152 entry->mode = default_mode;
153 strcpy(entry->devpath, devpath);
154 list_add(&entry->entry, &g_smscore_registry);
156 sms_err("failed to create smscore_registry.");
157 kmutex_unlock(&g_smscore_registrylock);
161 int smscore_registry_getmode(char *devpath)
163 struct smscore_registry_entry_t *entry;
165 entry = smscore_find_registry(devpath);
169 sms_err("No registry found.");
174 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
176 struct smscore_registry_entry_t *entry;
178 entry = smscore_find_registry(devpath);
182 sms_err("No registry found.");
187 void smscore_registry_setmode(char *devpath, int mode)
189 struct smscore_registry_entry_t *entry;
191 entry = smscore_find_registry(devpath);
195 sms_err("No registry found.");
198 static void smscore_registry_settype(char *devpath,
199 enum sms_device_type_st type)
201 struct smscore_registry_entry_t *entry;
203 entry = smscore_find_registry(devpath);
207 sms_err("No registry found.");
211 static void list_add_locked(struct list_head *new, struct list_head *head,
216 spin_lock_irqsave(lock, flags);
220 spin_unlock_irqrestore(lock, flags);
224 * register a client callback that called when device plugged in/unplugged
225 * NOTE: if devices exist callback is called immediately for each device
227 * @param hotplug callback
229 * @return 0 on success, <0 on error.
231 int smscore_register_hotplug(hotplug_t hotplug)
233 struct smscore_device_notifyee_t *notifyee;
234 struct list_head *next, *first;
237 kmutex_lock(&g_smscore_deviceslock);
239 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
242 /* now notify callback about existing devices */
243 first = &g_smscore_devices;
244 for (next = first->next;
245 next != first && !rc;
247 struct smscore_device_t *coredev =
248 (struct smscore_device_t *) next;
249 rc = hotplug(coredev, coredev->device, 1);
253 notifyee->hotplug = hotplug;
254 list_add(¬ifyee->entry, &g_smscore_notifyees);
260 kmutex_unlock(&g_smscore_deviceslock);
266 * unregister a client callback that called when device plugged in/unplugged
268 * @param hotplug callback
271 void smscore_unregister_hotplug(hotplug_t hotplug)
273 struct list_head *next, *first;
275 kmutex_lock(&g_smscore_deviceslock);
277 first = &g_smscore_notifyees;
279 for (next = first->next; next != first;) {
280 struct smscore_device_notifyee_t *notifyee =
281 (struct smscore_device_notifyee_t *) next;
284 if (notifyee->hotplug == hotplug) {
285 list_del(¬ifyee->entry);
290 kmutex_unlock(&g_smscore_deviceslock);
293 static void smscore_notify_clients(struct smscore_device_t *coredev)
295 struct smscore_client_t *client;
297 /* the client must call smscore_unregister_client from remove handler */
298 while (!list_empty(&coredev->clients)) {
299 client = (struct smscore_client_t *) coredev->clients.next;
300 client->onremove_handler(client->context);
304 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
305 struct device *device, int arrival)
307 struct list_head *next, *first;
310 /* note: must be called under g_deviceslock */
312 first = &g_smscore_notifyees;
314 for (next = first->next; next != first; next = next->next) {
315 rc = ((struct smscore_device_notifyee_t *) next)->
316 hotplug(coredev, device, arrival);
325 smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
326 dma_addr_t common_buffer_phys)
328 struct smscore_buffer_t *cb =
329 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
331 sms_info("kmalloc(...) failed");
336 cb->offset_in_common = buffer - (u8 *) common_buffer;
337 cb->phys = common_buffer_phys + cb->offset_in_common;
343 * creates coredev object for a device, prepares buffers,
344 * creates buffer mappings, notifies registered hotplugs about new device.
346 * @param params device pointer to struct with device specific parameters
348 * @param coredev pointer to a value that receives created coredev object
350 * @return 0 on success, <0 on error.
352 int smscore_register_device(struct smsdevice_params_t *params,
353 struct smscore_device_t **coredev)
355 struct smscore_device_t *dev;
358 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
360 sms_info("kzalloc(...) failed");
364 /* init list entry so it could be safe in smscore_unregister_device */
365 INIT_LIST_HEAD(&dev->entry);
368 INIT_LIST_HEAD(&dev->clients);
369 INIT_LIST_HEAD(&dev->buffers);
372 spin_lock_init(&dev->clientslock);
373 spin_lock_init(&dev->bufferslock);
375 /* init completion events */
376 init_completion(&dev->version_ex_done);
377 init_completion(&dev->data_download_done);
378 init_completion(&dev->trigger_done);
379 init_completion(&dev->init_device_done);
380 init_completion(&dev->reload_start_done);
381 init_completion(&dev->resume_done);
383 /* alloc common buffer */
384 dev->common_buffer_size = params->buffer_size * params->num_buffers;
385 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
386 &dev->common_buffer_phys,
387 GFP_KERNEL | GFP_DMA);
388 if (!dev->common_buffer) {
389 smscore_unregister_device(dev);
393 /* prepare dma buffers */
394 for (buffer = dev->common_buffer;
395 dev->num_buffers < params->num_buffers;
396 dev->num_buffers++, buffer += params->buffer_size) {
397 struct smscore_buffer_t *cb =
398 smscore_createbuffer(buffer, dev->common_buffer,
399 dev->common_buffer_phys);
401 smscore_unregister_device(dev);
405 smscore_putbuffer(dev, cb);
408 sms_info("allocated %d buffers", dev->num_buffers);
410 dev->mode = DEVICE_MODE_NONE;
411 dev->context = params->context;
412 dev->device = params->device;
413 dev->setmode_handler = params->setmode_handler;
414 dev->detectmode_handler = params->detectmode_handler;
415 dev->sendrequest_handler = params->sendrequest_handler;
416 dev->preload_handler = params->preload_handler;
417 dev->postload_handler = params->postload_handler;
419 dev->device_flags = params->flags;
420 strcpy(dev->devpath, params->devpath);
422 smscore_registry_settype(dev->devpath, params->device_type);
424 /* add device to devices list */
425 kmutex_lock(&g_smscore_deviceslock);
426 list_add(&dev->entry, &g_smscore_devices);
427 kmutex_unlock(&g_smscore_deviceslock);
431 sms_info("device %p created", dev);
437 * sets initial device mode and notifies client hotplugs that device is ready
439 * @param coredev pointer to a coredev object returned by
440 * smscore_register_device
442 * @return 0 on success, <0 on error.
444 int smscore_start_device(struct smscore_device_t *coredev)
446 int rc = smscore_set_device_mode(
447 coredev, smscore_registry_getmode(coredev->devpath));
449 sms_info("set device mode faile , rc %d", rc);
453 kmutex_lock(&g_smscore_deviceslock);
455 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
457 sms_info("device %p started, rc %d", coredev, rc);
459 kmutex_unlock(&g_smscore_deviceslock);
464 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
465 void *buffer, size_t size,
466 struct completion *completion)
468 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
470 sms_info("sendrequest returned error %d", rc);
474 return wait_for_completion_timeout(completion,
475 msecs_to_jiffies(10000)) ?
479 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
480 void *buffer, size_t size)
482 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
483 struct SmsMsgHdr_ST *msg;
484 u32 mem_address = firmware->StartAddress;
485 u8 *payload = firmware->Payload;
488 sms_info("loading FW to addr 0x%x size %d",
489 mem_address, firmware->Length);
490 if (coredev->preload_handler) {
491 rc = coredev->preload_handler(coredev->context);
496 /* PAGE_SIZE buffer shall be enough and dma aligned */
497 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
501 if (coredev->mode != DEVICE_MODE_NONE) {
502 sms_debug("sending reload command.");
503 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
504 sizeof(struct SmsMsgHdr_ST));
505 rc = smscore_sendrequest_and_wait(coredev, msg,
507 &coredev->reload_start_done);
508 mem_address = *(u32 *) &payload[20];
511 while (size && rc >= 0) {
512 struct SmsDataDownload_ST *DataMsg =
513 (struct SmsDataDownload_ST *) msg;
514 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
516 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
517 (u16)(sizeof(struct SmsMsgHdr_ST) +
518 sizeof(u32) + payload_size));
520 DataMsg->MemAddr = mem_address;
521 memcpy(DataMsg->Payload, payload, payload_size);
523 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
524 (coredev->mode == DEVICE_MODE_NONE))
525 rc = coredev->sendrequest_handler(
526 coredev->context, DataMsg,
527 DataMsg->xMsgHeader.msgLength);
529 rc = smscore_sendrequest_and_wait(
531 DataMsg->xMsgHeader.msgLength,
532 &coredev->data_download_done);
534 payload += payload_size;
535 size -= payload_size;
536 mem_address += payload_size;
540 if (coredev->mode == DEVICE_MODE_NONE) {
541 struct SmsMsgData_ST *TriggerMsg =
542 (struct SmsMsgData_ST *) msg;
544 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
545 sizeof(struct SmsMsgHdr_ST) +
548 TriggerMsg->msgData[0] = firmware->StartAddress;
550 TriggerMsg->msgData[1] = 5; /* Priority */
551 TriggerMsg->msgData[2] = 0x200; /* Stack size */
552 TriggerMsg->msgData[3] = 0; /* Parameter */
553 TriggerMsg->msgData[4] = 4; /* Task ID */
555 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
556 rc = coredev->sendrequest_handler(
557 coredev->context, TriggerMsg,
558 TriggerMsg->xMsgHeader.msgLength);
561 rc = smscore_sendrequest_and_wait(
563 TriggerMsg->xMsgHeader.msgLength,
564 &coredev->trigger_done);
566 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
567 sizeof(struct SmsMsgHdr_ST));
569 rc = coredev->sendrequest_handler(coredev->context,
570 msg, msg->msgLength);
575 sms_debug("rc=%d, postload=%p ", rc,
576 coredev->postload_handler);
580 return ((rc >= 0) && coredev->postload_handler) ?
581 coredev->postload_handler(coredev->context) :
586 * loads specified firmware into a buffer and calls device loadfirmware_handler
588 * @param coredev pointer to a coredev object returned by
589 * smscore_register_device
590 * @param filename null-terminated string specifies firmware file name
591 * @param loadfirmware_handler device handler that loads firmware
593 * @return 0 on success, <0 on error.
595 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
597 loadfirmware_t loadfirmware_handler)
600 const struct firmware *fw;
603 if (loadfirmware_handler == NULL && !(coredev->device_flags &
607 rc = request_firmware(&fw, filename, coredev->device);
609 sms_info("failed to open \"%s\"", filename);
612 sms_info("read FW %s, size=%zd", filename, fw->size);
613 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
614 GFP_KERNEL | GFP_DMA);
616 memcpy(fw_buffer, fw->data, fw->size);
618 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
619 smscore_load_firmware_family2(coredev,
622 loadfirmware_handler(coredev->context,
623 fw_buffer, fw->size);
627 sms_info("failed to allocate firmware buffer");
631 release_firmware(fw);
637 * notifies all clients registered with the device, notifies hotplugs,
638 * frees all buffers and coredev object
640 * @param coredev pointer to a coredev object returned by
641 * smscore_register_device
643 * @return 0 on success, <0 on error.
645 void smscore_unregister_device(struct smscore_device_t *coredev)
647 struct smscore_buffer_t *cb;
651 kmutex_lock(&g_smscore_deviceslock);
653 smscore_notify_clients(coredev);
654 smscore_notify_callbacks(coredev, NULL, 0);
656 /* at this point all buffers should be back
657 * onresponse must no longer be called */
660 while ((cb = smscore_getbuffer(coredev))) {
664 if (num_buffers == coredev->num_buffers)
667 sms_info("exiting although "
668 "not all buffers released.");
672 sms_info("waiting for %d buffer(s)",
673 coredev->num_buffers - num_buffers);
677 sms_info("freed %d buffers", num_buffers);
679 if (coredev->common_buffer)
680 dma_free_coherent(NULL, coredev->common_buffer_size,
681 coredev->common_buffer,
682 coredev->common_buffer_phys);
684 list_del(&coredev->entry);
687 kmutex_unlock(&g_smscore_deviceslock);
689 sms_info("device %p destroyed", coredev);
692 static int smscore_detect_mode(struct smscore_device_t *coredev)
694 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
695 GFP_KERNEL | GFP_DMA);
696 struct SmsMsgHdr_ST *msg =
697 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
703 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
704 sizeof(struct SmsMsgHdr_ST));
706 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
707 &coredev->version_ex_done);
709 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
711 if (wait_for_completion_timeout(&coredev->resume_done,
712 msecs_to_jiffies(5000))) {
713 rc = smscore_sendrequest_and_wait(
714 coredev, msg, msg->msgLength,
715 &coredev->version_ex_done);
717 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
718 "second try, rc %d", rc);
728 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
729 /*Stellar NOVA A0 Nova B0 VEGA*/
731 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
733 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
735 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
737 {"none", "none", "none", "none"},
739 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
741 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
743 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
745 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
748 static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
749 int mode, enum sms_device_type_st type)
751 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
752 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
756 * calls device handler to change mode of operation
757 * NOTE: stellar/usb may disconnect when changing mode
759 * @param coredev pointer to a coredev object returned by
760 * smscore_register_device
761 * @param mode requested mode of operation
763 * @return 0 on success, <0 on error.
765 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
769 enum sms_device_type_st type;
771 sms_debug("set device mode to %d", mode);
772 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
773 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
774 sms_err("invalid mode specified %d", mode);
778 smscore_registry_setmode(coredev->devpath, mode);
780 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
781 rc = smscore_detect_mode(coredev);
783 sms_err("mode detect failed %d", rc);
788 if (coredev->mode == mode) {
789 sms_info("device mode %d already set", mode);
793 if (!(coredev->modes_supported & (1 << mode))) {
796 type = smscore_registry_gettype(coredev->devpath);
797 fw_filename = sms_get_fw_name(coredev, mode, type);
799 rc = smscore_load_firmware_from_file(coredev,
802 sms_warn("error %d loading firmware: %s, "
803 "trying again with default firmware",
806 /* try again with the default firmware */
807 fw_filename = smscore_fw_lkup[mode][type];
808 rc = smscore_load_firmware_from_file(coredev,
812 sms_warn("error %d loading "
818 sms_log("firmware download success: %s", fw_filename);
820 sms_info("mode %d supported by running "
823 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
824 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
826 struct SmsMsgData_ST *msg =
827 (struct SmsMsgData_ST *)
828 SMS_ALIGN_ADDRESS(buffer);
830 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
831 sizeof(struct SmsMsgData_ST));
832 msg->msgData[0] = mode;
834 rc = smscore_sendrequest_and_wait(
835 coredev, msg, msg->xMsgHeader.msgLength,
836 &coredev->init_device_done);
840 sms_err("Could not allocate buffer for "
841 "init device message.");
845 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
846 sms_err("invalid mode specified %d", mode);
850 smscore_registry_setmode(coredev->devpath, mode);
852 if (coredev->detectmode_handler)
853 coredev->detectmode_handler(coredev->context,
856 if (coredev->mode != mode && coredev->setmode_handler)
857 rc = coredev->setmode_handler(coredev->context, mode);
861 coredev->mode = mode;
862 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
866 sms_err("return error code %d.", rc);
871 * calls device handler to get current mode of operation
873 * @param coredev pointer to a coredev object returned by
874 * smscore_register_device
876 * @return current mode
878 int smscore_get_device_mode(struct smscore_device_t *coredev)
880 return coredev->mode;
884 * find client by response id & type within the clients list.
885 * return client handle or NULL.
887 * @param coredev pointer to a coredev object returned by
888 * smscore_register_device
889 * @param data_type client data type (SMS_DONT_CARE for all types)
890 * @param id client id (SMS_DONT_CARE for all id)
894 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
895 int data_type, int id)
897 struct smscore_client_t *client = NULL;
898 struct list_head *next, *first;
900 struct list_head *firstid, *nextid;
903 spin_lock_irqsave(&coredev->clientslock, flags);
904 first = &coredev->clients;
905 for (next = first->next;
906 (next != first) && !client;
908 firstid = &((struct smscore_client_t *)next)->idlist;
909 for (nextid = firstid->next;
911 nextid = nextid->next) {
912 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
913 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
914 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
915 client = (struct smscore_client_t *) next;
920 spin_unlock_irqrestore(&coredev->clientslock, flags);
925 * find client by response id/type, call clients onresponse handler
926 * return buffer to pool on error
928 * @param coredev pointer to a coredev object returned by
929 * smscore_register_device
930 * @param cb pointer to response buffer descriptor
933 void smscore_onresponse(struct smscore_device_t *coredev,
934 struct smscore_buffer_t *cb)
936 struct SmsMsgHdr_ST *phdr =
937 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
938 struct smscore_client_t *client =
939 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
942 static unsigned long last_sample_time; /* = 0; */
943 static int data_total; /* = 0; */
944 unsigned long time_now = jiffies_to_msecs(jiffies);
946 if (!last_sample_time)
947 last_sample_time = time_now;
949 if (time_now - last_sample_time > 10000) {
950 sms_debug("\ndata rate %d bytes/secs",
951 (int)((data_total * 1000) /
952 (time_now - last_sample_time)));
954 last_sample_time = time_now;
958 data_total += cb->size;
959 /* If no client registered for type & id,
960 * check for control client where type is not registered */
962 rc = client->onresponse_handler(client->context, cb);
965 switch (phdr->msgType) {
966 case MSG_SMS_GET_VERSION_EX_RES:
968 struct SmsVersionRes_ST *ver =
969 (struct SmsVersionRes_ST *) phdr;
970 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
971 "id %d prots 0x%x ver %d.%d",
972 ver->FirmwareId, ver->SupportedProtocols,
973 ver->RomVersionMajor, ver->RomVersionMinor);
975 coredev->mode = ver->FirmwareId == 255 ?
976 DEVICE_MODE_NONE : ver->FirmwareId;
977 coredev->modes_supported = ver->SupportedProtocols;
979 complete(&coredev->version_ex_done);
982 case MSG_SMS_INIT_DEVICE_RES:
983 sms_debug("MSG_SMS_INIT_DEVICE_RES");
984 complete(&coredev->init_device_done);
986 case MSG_SW_RELOAD_START_RES:
987 sms_debug("MSG_SW_RELOAD_START_RES");
988 complete(&coredev->reload_start_done);
990 case MSG_SMS_DATA_DOWNLOAD_RES:
991 complete(&coredev->data_download_done);
993 case MSG_SW_RELOAD_EXEC_RES:
994 sms_debug("MSG_SW_RELOAD_EXEC_RES");
996 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
997 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
998 complete(&coredev->trigger_done);
1000 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1001 complete(&coredev->resume_done);
1006 smscore_putbuffer(coredev, cb);
1011 * return pointer to next free buffer descriptor from core pool
1013 * @param coredev pointer to a coredev object returned by
1014 * smscore_register_device
1016 * @return pointer to descriptor on success, NULL on error.
1018 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1020 struct smscore_buffer_t *cb = NULL;
1021 unsigned long flags;
1023 spin_lock_irqsave(&coredev->bufferslock, flags);
1025 if (!list_empty(&coredev->buffers)) {
1026 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1027 list_del(&cb->entry);
1030 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1036 * return buffer descriptor to a pool
1038 * @param coredev pointer to a coredev object returned by
1039 * smscore_register_device
1040 * @param cb pointer buffer descriptor
1043 void smscore_putbuffer(struct smscore_device_t *coredev,
1044 struct smscore_buffer_t *cb)
1046 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1049 static int smscore_validate_client(struct smscore_device_t *coredev,
1050 struct smscore_client_t *client,
1051 int data_type, int id)
1053 struct smscore_idlist_t *listentry;
1054 struct smscore_client_t *registered_client;
1057 sms_err("bad parameter.");
1060 registered_client = smscore_find_client(coredev, data_type, id);
1061 if (registered_client == client)
1064 if (registered_client) {
1065 sms_err("The msg ID already registered to another client.");
1068 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1070 sms_err("Can't allocate memory for client id.");
1074 listentry->data_type = data_type;
1075 list_add_locked(&listentry->entry, &client->idlist,
1076 &coredev->clientslock);
1081 * creates smsclient object, check that id is taken by another client
1083 * @param coredev pointer to a coredev object from clients hotplug
1084 * @param initial_id all messages with this id would be sent to this client
1085 * @param data_type all messages of this type would be sent to this client
1086 * @param onresponse_handler client handler that is called to
1087 * process incoming messages
1088 * @param onremove_handler client handler that is called when device is removed
1089 * @param context client-specific context
1090 * @param client pointer to a value that receives created smsclient object
1092 * @return 0 on success, <0 on error.
1094 int smscore_register_client(struct smscore_device_t *coredev,
1095 struct smsclient_params_t *params,
1096 struct smscore_client_t **client)
1098 struct smscore_client_t *newclient;
1099 /* check that no other channel with same parameters exists */
1100 if (smscore_find_client(coredev, params->data_type,
1101 params->initial_id)) {
1102 sms_err("Client already exist.");
1106 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1108 sms_err("Failed to allocate memory for client.");
1112 INIT_LIST_HEAD(&newclient->idlist);
1113 newclient->coredev = coredev;
1114 newclient->onresponse_handler = params->onresponse_handler;
1115 newclient->onremove_handler = params->onremove_handler;
1116 newclient->context = params->context;
1117 list_add_locked(&newclient->entry, &coredev->clients,
1118 &coredev->clientslock);
1119 smscore_validate_client(coredev, newclient, params->data_type,
1120 params->initial_id);
1121 *client = newclient;
1122 sms_debug("%p %d %d", params->context, params->data_type,
1123 params->initial_id);
1129 * frees smsclient object and all subclients associated with it
1131 * @param client pointer to smsclient object returned by
1132 * smscore_register_client
1135 void smscore_unregister_client(struct smscore_client_t *client)
1137 struct smscore_device_t *coredev = client->coredev;
1138 unsigned long flags;
1140 spin_lock_irqsave(&coredev->clientslock, flags);
1143 while (!list_empty(&client->idlist)) {
1144 struct smscore_idlist_t *identry =
1145 (struct smscore_idlist_t *) client->idlist.next;
1146 list_del(&identry->entry);
1150 sms_info("%p", client->context);
1152 list_del(&client->entry);
1155 spin_unlock_irqrestore(&coredev->clientslock, flags);
1159 * verifies that source id is not taken by another client,
1160 * calls device handler to send requests to the device
1162 * @param client pointer to smsclient object returned by
1163 * smscore_register_client
1164 * @param buffer pointer to a request buffer
1165 * @param size size (in bytes) of request buffer
1167 * @return 0 on success, <0 on error.
1169 int smsclient_sendrequest(struct smscore_client_t *client,
1170 void *buffer, size_t size)
1172 struct smscore_device_t *coredev;
1173 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1176 if (client == NULL) {
1177 sms_err("Got NULL client");
1181 coredev = client->coredev;
1183 /* check that no other channel with same id exists */
1184 if (coredev == NULL) {
1185 sms_err("Got NULL coredev");
1189 rc = smscore_validate_client(client->coredev, client, 0,
1194 return coredev->sendrequest_handler(coredev->context, buffer, size);
1198 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1199 struct smscore_gpio_config *pinconfig)
1202 struct SmsMsgHdr_ST hdr;
1206 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1207 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1208 msg.hdr.msgDstId = HIF_TASK;
1209 msg.hdr.msgFlags = 0;
1210 msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1211 msg.hdr.msgLength = sizeof(msg);
1214 msg.data[1] = pinconfig->pullupdown;
1216 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1217 msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1219 switch (pinconfig->outputdriving) {
1220 case SMS_GPIO_OUTPUTDRIVING_16mA:
1221 msg.data[3] = 7; /* Nova - 16mA */
1223 case SMS_GPIO_OUTPUTDRIVING_12mA:
1224 msg.data[3] = 5; /* Nova - 11mA */
1226 case SMS_GPIO_OUTPUTDRIVING_8mA:
1227 msg.data[3] = 3; /* Nova - 7mA */
1229 case SMS_GPIO_OUTPUTDRIVING_4mA:
1231 msg.data[3] = 2; /* Nova - 4mA */
1235 msg.data[4] = pinconfig->direction;
1237 } else /* TODO: SMS_DEVICE_FAMILY1 */
1240 return coredev->sendrequest_handler(coredev->context,
1244 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1247 struct SmsMsgHdr_ST hdr;
1251 if (pin > MAX_GPIO_PIN_NUMBER)
1254 msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1255 msg.hdr.msgDstId = HIF_TASK;
1256 msg.hdr.msgFlags = 0;
1257 msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1258 msg.hdr.msgLength = sizeof(msg);
1261 msg.data[1] = level ? 1 : 0;
1264 return coredev->sendrequest_handler(coredev->context,
1268 static int __init smscore_module_init(void)
1272 INIT_LIST_HEAD(&g_smscore_notifyees);
1273 INIT_LIST_HEAD(&g_smscore_devices);
1274 kmutex_init(&g_smscore_deviceslock);
1276 INIT_LIST_HEAD(&g_smscore_registry);
1277 kmutex_init(&g_smscore_registrylock);
1280 rc = smsusb_register();
1283 rc = smsdvb_register();
1285 sms_debug("rc %d", rc);
1290 static void __exit smscore_module_exit(void)
1293 kmutex_lock(&g_smscore_deviceslock);
1294 while (!list_empty(&g_smscore_notifyees)) {
1295 struct smscore_device_notifyee_t *notifyee =
1296 (struct smscore_device_notifyee_t *)
1297 g_smscore_notifyees.next;
1299 list_del(¬ifyee->entry);
1302 kmutex_unlock(&g_smscore_deviceslock);
1304 kmutex_lock(&g_smscore_registrylock);
1305 while (!list_empty(&g_smscore_registry)) {
1306 struct smscore_registry_entry_t *entry =
1307 (struct smscore_registry_entry_t *)
1308 g_smscore_registry.next;
1310 list_del(&entry->entry);
1313 kmutex_unlock(&g_smscore_registrylock);
1315 /* DVB UnRegister */
1316 smsdvb_unregister();
1318 /* Unregister USB */
1319 smsusb_unregister();
1324 module_init(smscore_module_init);
1325 module_exit(smscore_module_exit);
1327 MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
1328 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1329 MODULE_LICENSE("GPL");