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 3 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"
37 module_param_named(debug, sms_debug, int, 0644);
38 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
40 #define PERROR(fmt, args...)\
41 sms_err("smscore error: line %d- %s(): " fmt, \
42 __LINE__, __func__, ## args)
46 # define PWARNING(fmt, args...) sms_info("smscore warning: " \
47 "line %d- %s(): " fmt, \
48 __LINE__, __func__, ## args)
49 #undef PDEBUG /* undef it, just in case */
50 # define PDEBUG(fmt, args...) sms_info("smscore - %s(): " fmt, \
52 #else /*SMSCORE_DEBUG*/
53 #define PDEBUG(fmt, args...)
54 #define PWARNING(fmt, args...)
57 struct smscore_device_notifyee_t {
58 struct list_head entry;
62 struct smscore_idlist_t {
63 struct list_head entry;
68 struct smscore_client_t {
69 struct list_head entry;
70 struct smscore_device_t *coredev;
72 struct list_head idlist;
73 onresponse_t onresponse_handler;
74 onremove_t onremove_handler;
77 struct smscore_device_t {
78 struct list_head entry;
80 struct list_head clients;
81 struct list_head subclients;
82 spinlock_t clientslock;
84 struct list_head buffers;
85 spinlock_t bufferslock;
89 int common_buffer_size;
90 dma_addr_t common_buffer_phys;
93 struct device *device;
96 unsigned long device_flags;
98 setmode_t setmode_handler;
99 detectmode_t detectmode_handler;
100 sendrequest_t sendrequest_handler;
101 preload_t preload_handler;
102 postload_t postload_handler;
104 int mode, modes_supported;
106 struct completion version_ex_done, data_download_done, trigger_done;
107 struct completion init_device_done, reload_start_done, resume_done;
112 void smscore_set_board_id(struct smscore_device_t *core, int id)
117 int smscore_get_board_id(struct smscore_device_t *core)
119 return core->board_id;
122 struct smscore_registry_entry_t {
123 struct list_head entry;
126 enum sms_device_type_st type;
129 struct list_head g_smscore_notifyees;
130 struct list_head g_smscore_devices;
131 kmutex_t g_smscore_deviceslock;
133 struct list_head g_smscore_registry;
134 kmutex_t g_smscore_registrylock;
136 static int default_mode = 4;
138 module_param(default_mode, int, 0644);
139 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
141 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
143 struct smscore_registry_entry_t *entry;
144 struct list_head *next;
146 kmutex_lock(&g_smscore_registrylock);
147 for (next = g_smscore_registry.next;
148 next != &g_smscore_registry;
150 entry = (struct smscore_registry_entry_t *) next;
151 if (!strcmp(entry->devpath, devpath)) {
152 kmutex_unlock(&g_smscore_registrylock);
156 entry = (struct smscore_registry_entry_t *)
157 kmalloc(sizeof(struct smscore_registry_entry_t),
160 entry->mode = default_mode;
161 strcpy(entry->devpath, devpath);
162 list_add(&entry->entry, &g_smscore_registry);
164 sms_err("failed to create smscore_registry.");
165 kmutex_unlock(&g_smscore_registrylock);
169 int smscore_registry_getmode(char *devpath)
171 struct smscore_registry_entry_t *entry;
173 entry = smscore_find_registry(devpath);
177 sms_err("No registry found.");
182 enum sms_device_type_st smscore_registry_gettype(char *devpath)
184 struct smscore_registry_entry_t *entry;
186 entry = smscore_find_registry(devpath);
190 sms_err("No registry found.");
195 void smscore_registry_setmode(char *devpath, int mode)
197 struct smscore_registry_entry_t *entry;
199 entry = smscore_find_registry(devpath);
203 sms_err("No registry found.");
206 void smscore_registry_settype(char *devpath, enum sms_device_type_st type)
208 struct smscore_registry_entry_t *entry;
210 entry = smscore_find_registry(devpath);
214 sms_err("No registry found.");
218 void list_add_locked(struct list_head *new, struct list_head *head,
223 spin_lock_irqsave(lock, flags);
227 spin_unlock_irqrestore(lock, flags);
231 * register a client callback that called when device plugged in/unplugged
232 * NOTE: if devices exist callback is called immediately for each device
234 * @param hotplug callback
236 * @return 0 on success, <0 on error.
238 int smscore_register_hotplug(hotplug_t hotplug)
240 struct smscore_device_notifyee_t *notifyee;
241 struct list_head *next, *first;
244 kmutex_lock(&g_smscore_deviceslock);
246 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
249 /* now notify callback about existing devices */
250 first = &g_smscore_devices;
251 for (next = first->next;
252 next != first && !rc;
254 struct smscore_device_t *coredev =
255 (struct smscore_device_t *) next;
256 rc = hotplug(coredev, coredev->device, 1);
260 notifyee->hotplug = hotplug;
261 list_add(¬ifyee->entry, &g_smscore_notifyees);
267 kmutex_unlock(&g_smscore_deviceslock);
273 * unregister a client callback that called when device plugged in/unplugged
275 * @param hotplug callback
278 void smscore_unregister_hotplug(hotplug_t hotplug)
280 struct list_head *next, *first;
282 kmutex_lock(&g_smscore_deviceslock);
284 first = &g_smscore_notifyees;
286 for (next = first->next; next != first;) {
287 struct smscore_device_notifyee_t *notifyee =
288 (struct smscore_device_notifyee_t *) next;
291 if (notifyee->hotplug == hotplug) {
292 list_del(¬ifyee->entry);
297 kmutex_unlock(&g_smscore_deviceslock);
300 void smscore_notify_clients(struct smscore_device_t *coredev)
302 struct smscore_client_t *client;
304 /* the client must call smscore_unregister_client from remove handler */
305 while (!list_empty(&coredev->clients)) {
306 client = (struct smscore_client_t *) coredev->clients.next;
307 client->onremove_handler(client->context);
311 int smscore_notify_callbacks(struct smscore_device_t *coredev,
312 struct device *device, int arrival)
314 struct list_head *next, *first;
317 /* note: must be called under g_deviceslock */
319 first = &g_smscore_notifyees;
321 for (next = first->next; next != first; next = next->next) {
322 rc = ((struct smscore_device_notifyee_t *) next)->
323 hotplug(coredev, device, arrival);
331 struct smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
332 dma_addr_t common_buffer_phys)
334 struct smscore_buffer_t *cb =
335 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
337 sms_info("kmalloc(...) failed");
342 cb->offset_in_common = buffer - (u8 *) common_buffer;
343 cb->phys = common_buffer_phys + cb->offset_in_common;
349 * creates coredev object for a device, prepares buffers,
350 * creates buffer mappings, notifies registered hotplugs about new device.
352 * @param params device pointer to struct with device specific parameters
354 * @param coredev pointer to a value that receives created coredev object
356 * @return 0 on success, <0 on error.
358 int smscore_register_device(struct smsdevice_params_t *params,
359 struct smscore_device_t **coredev)
361 struct smscore_device_t *dev;
364 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
366 sms_info("kzalloc(...) failed");
370 /* init list entry so it could be safe in smscore_unregister_device */
371 INIT_LIST_HEAD(&dev->entry);
374 INIT_LIST_HEAD(&dev->clients);
375 INIT_LIST_HEAD(&dev->buffers);
378 spin_lock_init(&dev->clientslock);
379 spin_lock_init(&dev->bufferslock);
381 /* init completion events */
382 init_completion(&dev->version_ex_done);
383 init_completion(&dev->data_download_done);
384 init_completion(&dev->trigger_done);
385 init_completion(&dev->init_device_done);
386 init_completion(&dev->reload_start_done);
387 init_completion(&dev->resume_done);
389 /* alloc common buffer */
390 dev->common_buffer_size = params->buffer_size * params->num_buffers;
391 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
392 &dev->common_buffer_phys,
393 GFP_KERNEL | GFP_DMA);
394 if (!dev->common_buffer) {
395 smscore_unregister_device(dev);
399 /* prepare dma buffers */
400 for (buffer = dev->common_buffer;
401 dev->num_buffers < params->num_buffers;
402 dev->num_buffers++, buffer += params->buffer_size) {
403 struct smscore_buffer_t *cb =
404 smscore_createbuffer(buffer, dev->common_buffer,
405 dev->common_buffer_phys);
407 smscore_unregister_device(dev);
411 smscore_putbuffer(dev, cb);
414 sms_info("allocated %d buffers", dev->num_buffers);
416 dev->mode = DEVICE_MODE_NONE;
417 dev->context = params->context;
418 dev->device = params->device;
419 dev->setmode_handler = params->setmode_handler;
420 dev->detectmode_handler = params->detectmode_handler;
421 dev->sendrequest_handler = params->sendrequest_handler;
422 dev->preload_handler = params->preload_handler;
423 dev->postload_handler = params->postload_handler;
425 dev->device_flags = params->flags;
426 strcpy(dev->devpath, params->devpath);
428 smscore_registry_settype(dev->devpath, params->device_type);
430 /* add device to devices list */
431 kmutex_lock(&g_smscore_deviceslock);
432 list_add(&dev->entry, &g_smscore_devices);
433 kmutex_unlock(&g_smscore_deviceslock);
437 sms_info("device %p created", dev);
443 * sets initial device mode and notifies client hotplugs that device is ready
445 * @param coredev pointer to a coredev object returned by
446 * smscore_register_device
448 * @return 0 on success, <0 on error.
450 int smscore_start_device(struct smscore_device_t *coredev)
452 int rc = smscore_set_device_mode(
453 coredev, smscore_registry_getmode(coredev->devpath));
455 sms_info("set device mode faile , rc %d", rc);
459 kmutex_lock(&g_smscore_deviceslock);
461 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
463 sms_info("device %p started, rc %d", coredev, rc);
465 kmutex_unlock(&g_smscore_deviceslock);
470 int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer,
471 size_t size, struct completion *completion)
473 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
475 sms_info("sendrequest returned error %d", rc);
479 return wait_for_completion_timeout(completion,
480 msecs_to_jiffies(10000)) ?
484 int smscore_load_firmware_family2(struct smscore_device_t *coredev,
485 void *buffer, size_t size)
487 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
488 struct SmsMsgHdr_ST *msg;
489 u32 mem_address = firmware->StartAddress;
490 u8 *payload = firmware->Payload;
493 sms_info("loading FW to addr 0x%x size %d",
494 mem_address, firmware->Length);
495 if (coredev->preload_handler) {
496 rc = coredev->preload_handler(coredev->context);
501 /* PAGE_SIZE buffer shall be enough and dma aligned */
502 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
506 if (coredev->mode != DEVICE_MODE_NONE) {
507 PDEBUG("Sending reload command");
508 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
509 sizeof(struct SmsMsgHdr_ST));
510 rc = smscore_sendrequest_and_wait(coredev, msg,
512 &coredev->reload_start_done);
513 mem_address = *(u32 *) &payload[20];
516 while (size && rc >= 0) {
517 struct SmsDataDownload_ST *DataMsg =
518 (struct SmsDataDownload_ST *) msg;
519 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
521 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
522 (u16)(sizeof(struct SmsMsgHdr_ST) +
523 sizeof(u32) + payload_size));
525 DataMsg->MemAddr = mem_address;
526 memcpy(DataMsg->Payload, payload, payload_size);
528 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
529 (coredev->mode == DEVICE_MODE_NONE))
530 rc = coredev->sendrequest_handler(
531 coredev->context, DataMsg,
532 DataMsg->xMsgHeader.msgLength);
534 rc = smscore_sendrequest_and_wait(
536 DataMsg->xMsgHeader.msgLength,
537 &coredev->data_download_done);
539 payload += payload_size;
540 size -= payload_size;
541 mem_address += payload_size;
545 if (coredev->mode == DEVICE_MODE_NONE) {
546 struct SmsMsgData_ST *TriggerMsg =
547 (struct SmsMsgData_ST *) msg;
549 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
550 sizeof(struct SmsMsgHdr_ST) +
553 TriggerMsg->msgData[0] = firmware->StartAddress;
555 TriggerMsg->msgData[1] = 5; /* Priority */
556 TriggerMsg->msgData[2] = 0x200; /* Stack size */
557 TriggerMsg->msgData[3] = 0; /* Parameter */
558 TriggerMsg->msgData[4] = 4; /* Task ID */
560 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
561 rc = coredev->sendrequest_handler(
562 coredev->context, TriggerMsg,
563 TriggerMsg->xMsgHeader.msgLength);
566 rc = smscore_sendrequest_and_wait(
568 TriggerMsg->xMsgHeader.msgLength,
569 &coredev->trigger_done);
571 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
572 sizeof(struct SmsMsgHdr_ST));
574 rc = coredev->sendrequest_handler(coredev->context,
575 msg, msg->msgLength);
580 sms_debug("rc=%d, postload=%p ", rc,
581 coredev->postload_handler);
585 return ((rc >= 0) && coredev->postload_handler) ?
586 coredev->postload_handler(coredev->context) :
591 * loads specified firmware into a buffer and calls device loadfirmware_handler
593 * @param coredev pointer to a coredev object returned by
594 * smscore_register_device
595 * @param filename null-terminated string specifies firmware file name
596 * @param loadfirmware_handler device handler that loads firmware
598 * @return 0 on success, <0 on error.
600 int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
602 loadfirmware_t loadfirmware_handler)
605 const struct firmware *fw;
608 if (loadfirmware_handler == NULL && !(coredev->device_flags &
612 rc = request_firmware(&fw, filename, coredev->device);
614 sms_info("failed to open \"%s\"", filename);
617 sms_info("read FW %s, size=%d\"", filename, fw->size);
618 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
619 GFP_KERNEL | GFP_DMA);
621 memcpy(fw_buffer, fw->data, fw->size);
623 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
624 smscore_load_firmware_family2(coredev,
627 loadfirmware_handler(coredev->context,
628 fw_buffer, fw->size);
632 sms_info("failed to allocate firmware buffer");
636 release_firmware(fw);
641 int smscore_load_firmware_from_buffer(struct smscore_device_t *coredev,
642 u8 *buffer, int size, int new_mode)
644 PERROR("Feature not implemented yet");
649 * notifies all clients registered with the device, notifies hotplugs,
650 * frees all buffers and coredev object
652 * @param coredev pointer to a coredev object returned by
653 * smscore_register_device
655 * @return 0 on success, <0 on error.
657 void smscore_unregister_device(struct smscore_device_t *coredev)
659 struct smscore_buffer_t *cb;
663 kmutex_lock(&g_smscore_deviceslock);
665 smscore_notify_clients(coredev);
666 smscore_notify_callbacks(coredev, NULL, 0);
668 /* at this point all buffers should be back
669 * onresponse must no longer be called */
672 while ((cb = smscore_getbuffer(coredev))) {
676 if (num_buffers == coredev->num_buffers)
679 sms_info("exiting although "
680 "not all buffers released.");
684 sms_info("waiting for %d buffer(s)",
685 coredev->num_buffers - num_buffers);
689 sms_info("freed %d buffers", num_buffers);
691 if (coredev->common_buffer)
692 dma_free_coherent(NULL, coredev->common_buffer_size,
693 coredev->common_buffer,
694 coredev->common_buffer_phys);
696 list_del(&coredev->entry);
699 kmutex_unlock(&g_smscore_deviceslock);
701 sms_info("device %p destroyed", coredev);
704 int smscore_detect_mode(struct smscore_device_t *coredev)
706 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
707 GFP_KERNEL | GFP_DMA);
708 struct SmsMsgHdr_ST *msg =
709 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
715 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
716 sizeof(struct SmsMsgHdr_ST));
718 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
719 &coredev->version_ex_done);
721 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
723 if (wait_for_completion_timeout(&coredev->resume_done,
724 msecs_to_jiffies(5000))) {
725 rc = smscore_sendrequest_and_wait(
726 coredev, msg, msg->msgLength,
727 &coredev->version_ex_done);
729 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
730 "second try, rc %d", rc);
740 char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
741 /*Stellar NOVA A0 Nova B0 VEGA*/
743 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
745 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
747 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
749 {"none", "none", "none", "none"},
751 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
753 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
755 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
757 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
762 * calls device handler to change mode of operation
763 * NOTE: stellar/usb may disconnect when changing mode
765 * @param coredev pointer to a coredev object returned by
766 * smscore_register_device
767 * @param mode requested mode of operation
769 * @return 0 on success, <0 on error.
771 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
775 enum sms_device_type_st type;
777 PDEBUG("set device mode to %d", mode);
778 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
779 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
780 sms_err("invalid mode specified %d", mode);
784 smscore_registry_setmode(coredev->devpath, mode);
786 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
787 rc = smscore_detect_mode(coredev);
789 sms_err("mode detect failed %d", rc);
794 if (coredev->mode == mode) {
795 sms_info("device mode %d already set", mode);
799 if (!(coredev->modes_supported & (1 << mode))) {
800 type = smscore_registry_gettype(coredev->devpath);
801 rc = smscore_load_firmware_from_file(
802 coredev, smscore_fw_lkup[mode][type], NULL);
804 sms_err("load firmware failed %d", rc);
808 sms_info("mode %d supported by running "
811 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
812 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
814 struct SmsMsgData_ST *msg =
815 (struct SmsMsgData_ST *)
816 SMS_ALIGN_ADDRESS(buffer);
818 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
819 sizeof(struct SmsMsgData_ST));
820 msg->msgData[0] = mode;
822 rc = smscore_sendrequest_and_wait(
823 coredev, msg, msg->xMsgHeader.msgLength,
824 &coredev->init_device_done);
828 sms_err("Could not allocate buffer for "
829 "init device message.");
833 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
834 sms_err("invalid mode specified %d", mode);
838 smscore_registry_setmode(coredev->devpath, mode);
840 if (coredev->detectmode_handler)
841 coredev->detectmode_handler(coredev->context,
844 if (coredev->mode != mode && coredev->setmode_handler)
845 rc = coredev->setmode_handler(coredev->context, mode);
849 coredev->mode = mode;
850 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
854 sms_err("return error code %d.", rc);
859 * calls device handler to get current mode of operation
861 * @param coredev pointer to a coredev object returned by
862 * smscore_register_device
864 * @return current mode
866 int smscore_get_device_mode(struct smscore_device_t *coredev)
868 return coredev->mode;
872 * find client by response id & type within the clients list.
873 * return client handle or NULL.
875 * @param coredev pointer to a coredev object returned by
876 * smscore_register_device
877 * @param data_type client data type (SMS_DONT_CARE for all types)
878 * @param id client id (SMS_DONT_CARE for all id)
881 struct smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
882 int data_type, int id)
884 struct smscore_client_t *client = NULL;
885 struct list_head *next, *first;
887 struct list_head *firstid, *nextid;
890 spin_lock_irqsave(&coredev->clientslock, flags);
891 first = &coredev->clients;
892 for (next = first->next;
893 (next != first) && !client;
895 firstid = &((struct smscore_client_t *)next)->idlist;
896 for (nextid = firstid->next;
898 nextid = nextid->next) {
899 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
900 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
901 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
902 client = (struct smscore_client_t *) next;
907 spin_unlock_irqrestore(&coredev->clientslock, flags);
912 * find client by response id/type, call clients onresponse handler
913 * return buffer to pool on error
915 * @param coredev pointer to a coredev object returned by
916 * smscore_register_device
917 * @param cb pointer to response buffer descriptor
920 void smscore_onresponse(struct smscore_device_t *coredev,
921 struct smscore_buffer_t *cb)
923 struct SmsMsgHdr_ST *phdr =
924 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
925 struct smscore_client_t *client =
926 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
929 static unsigned long last_sample_time; /* = 0; */
930 static int data_total; /* = 0; */
931 unsigned long time_now = jiffies_to_msecs(jiffies);
933 if (!last_sample_time)
934 last_sample_time = time_now;
936 if (time_now - last_sample_time > 10000) {
937 sms_debug("\ndata rate %d bytes/secs",
938 (int)((data_total * 1000) /
939 (time_now - last_sample_time)));
941 last_sample_time = time_now;
945 data_total += cb->size;
946 /* If no client registered for type & id,
947 * check for control client where type is not registered */
949 rc = client->onresponse_handler(client->context, cb);
952 switch (phdr->msgType) {
953 case MSG_SMS_GET_VERSION_EX_RES:
955 struct SmsVersionRes_ST *ver =
956 (struct SmsVersionRes_ST *) phdr;
957 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
958 "id %d prots 0x%x ver %d.%d",
959 ver->FirmwareId, ver->SupportedProtocols,
960 ver->RomVersionMajor, ver->RomVersionMinor);
962 coredev->mode = ver->FirmwareId == 255 ?
963 DEVICE_MODE_NONE : ver->FirmwareId;
964 coredev->modes_supported = ver->SupportedProtocols;
966 complete(&coredev->version_ex_done);
969 case MSG_SMS_INIT_DEVICE_RES:
970 sms_debug("MSG_SMS_INIT_DEVICE_RES");
971 complete(&coredev->init_device_done);
973 case MSG_SW_RELOAD_START_RES:
974 sms_debug("MSG_SW_RELOAD_START_RES");
975 complete(&coredev->reload_start_done);
977 case MSG_SMS_DATA_DOWNLOAD_RES:
978 complete(&coredev->data_download_done);
980 case MSG_SW_RELOAD_EXEC_RES:
981 sms_debug("MSG_SW_RELOAD_EXEC_RES");
983 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
984 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
985 complete(&coredev->trigger_done);
987 case MSG_SMS_SLEEP_RESUME_COMP_IND:
988 complete(&coredev->resume_done);
993 smscore_putbuffer(coredev, cb);
998 * return pointer to next free buffer descriptor from core pool
1000 * @param coredev pointer to a coredev object returned by
1001 * smscore_register_device
1003 * @return pointer to descriptor on success, NULL on error.
1005 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1007 struct smscore_buffer_t *cb = NULL;
1008 unsigned long flags;
1010 spin_lock_irqsave(&coredev->bufferslock, flags);
1012 if (!list_empty(&coredev->buffers)) {
1013 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1014 list_del(&cb->entry);
1017 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1023 * return buffer descriptor to a pool
1025 * @param coredev pointer to a coredev object returned by
1026 * smscore_register_device
1027 * @param cb pointer buffer descriptor
1030 void smscore_putbuffer(struct smscore_device_t *coredev,
1031 struct smscore_buffer_t *cb)
1033 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1036 int smscore_validate_client(struct smscore_device_t *coredev,
1037 struct smscore_client_t *client,
1038 int data_type, int id)
1040 struct smscore_idlist_t *listentry;
1041 struct smscore_client_t *registered_client;
1044 PERROR("bad parameter.");
1047 registered_client = smscore_find_client(coredev, data_type, id);
1048 if (registered_client == client)
1051 if (registered_client) {
1052 PERROR("The msg ID already registered to another client.");
1055 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1057 PERROR("Can't allocate memory for client id.");
1061 listentry->data_type = data_type;
1062 list_add_locked(&listentry->entry, &client->idlist,
1063 &coredev->clientslock);
1068 * creates smsclient object, check that id is taken by another client
1070 * @param coredev pointer to a coredev object from clients hotplug
1071 * @param initial_id all messages with this id would be sent to this client
1072 * @param data_type all messages of this type would be sent to this client
1073 * @param onresponse_handler client handler that is called to
1074 * process incoming messages
1075 * @param onremove_handler client handler that is called when device is removed
1076 * @param context client-specific context
1077 * @param client pointer to a value that receives created smsclient object
1079 * @return 0 on success, <0 on error.
1081 int smscore_register_client(struct smscore_device_t *coredev,
1082 struct smsclient_params_t *params,
1083 struct smscore_client_t **client)
1085 struct smscore_client_t *newclient;
1086 /* check that no other channel with same parameters exists */
1087 if (smscore_find_client(coredev, params->data_type,
1088 params->initial_id)) {
1089 PERROR("Client already exist.");
1093 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1095 PERROR("Failed to allocate memory for client.");
1099 INIT_LIST_HEAD(&newclient->idlist);
1100 newclient->coredev = coredev;
1101 newclient->onresponse_handler = params->onresponse_handler;
1102 newclient->onremove_handler = params->onremove_handler;
1103 newclient->context = params->context;
1104 list_add_locked(&newclient->entry, &coredev->clients,
1105 &coredev->clientslock);
1106 smscore_validate_client(coredev, newclient, params->data_type,
1107 params->initial_id);
1108 *client = newclient;
1109 PDEBUG("%p %d %d", params->context, params->data_type,
1110 params->initial_id);
1116 * frees smsclient object and all subclients associated with it
1118 * @param client pointer to smsclient object returned by
1119 * smscore_register_client
1122 void smscore_unregister_client(struct smscore_client_t *client)
1124 struct smscore_device_t *coredev = client->coredev;
1125 unsigned long flags;
1127 spin_lock_irqsave(&coredev->clientslock, flags);
1130 while (!list_empty(&client->idlist)) {
1131 struct smscore_idlist_t *identry =
1132 (struct smscore_idlist_t *) client->idlist.next;
1133 list_del(&identry->entry);
1137 sms_info("%p", client->context);
1139 list_del(&client->entry);
1142 spin_unlock_irqrestore(&coredev->clientslock, flags);
1146 * verifies that source id is not taken by another client,
1147 * calls device handler to send requests to the device
1149 * @param client pointer to smsclient object returned by
1150 * smscore_register_client
1151 * @param buffer pointer to a request buffer
1152 * @param size size (in bytes) of request buffer
1154 * @return 0 on success, <0 on error.
1156 int smsclient_sendrequest(struct smscore_client_t *client,
1157 void *buffer, size_t size)
1159 struct smscore_device_t *coredev;
1160 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1163 if (client == NULL) {
1164 sms_err("Got NULL client");
1168 coredev = client->coredev;
1170 /* check that no other channel with same id exists */
1171 if (coredev == NULL) {
1172 sms_err("Got NULL coredev");
1176 rc = smscore_validate_client(client->coredev, client, 0,
1181 return coredev->sendrequest_handler(coredev->context, buffer, size);
1185 * return the size of large (common) buffer
1187 * @param coredev pointer to a coredev object from clients hotplug
1189 * @return size (in bytes) of the buffer
1191 int smscore_get_common_buffer_size(struct smscore_device_t *coredev)
1193 return coredev->common_buffer_size;
1197 * maps common buffer (if supported by platform)
1199 * @param coredev pointer to a coredev object from clients hotplug
1200 * @param vma pointer to vma struct from mmap handler
1202 * @return 0 on success, <0 on error.
1204 int smscore_map_common_buffer(struct smscore_device_t *coredev,
1205 struct vm_area_struct *vma)
1207 unsigned long end = vma->vm_end,
1208 start = vma->vm_start,
1209 size = PAGE_ALIGN(coredev->common_buffer_size);
1211 if (!(vma->vm_flags & (VM_READ | VM_SHARED)) ||
1212 (vma->vm_flags & VM_WRITE)) {
1213 sms_err("invalid vm flags");
1217 if ((end - start) != size) {
1218 sms_err("invalid size %d expected %d",
1219 (int)(end - start), (int) size);
1223 if (remap_pfn_range(vma, start,
1224 coredev->common_buffer_phys >> PAGE_SHIFT,
1225 size, pgprot_noncached(vma->vm_page_prot))) {
1226 sms_err("remap_page_range failed");
1233 int smscore_module_init(void)
1237 INIT_LIST_HEAD(&g_smscore_notifyees);
1238 INIT_LIST_HEAD(&g_smscore_devices);
1239 kmutex_init(&g_smscore_deviceslock);
1241 INIT_LIST_HEAD(&g_smscore_registry);
1242 kmutex_init(&g_smscore_registrylock);
1245 rc = smsusb_register();
1248 rc = smsdvb_register();
1250 sms_debug("rc %d", rc);
1255 void smscore_module_exit(void)
1258 kmutex_lock(&g_smscore_deviceslock);
1259 while (!list_empty(&g_smscore_notifyees)) {
1260 struct smscore_device_notifyee_t *notifyee =
1261 (struct smscore_device_notifyee_t *)
1262 g_smscore_notifyees.next;
1264 list_del(¬ifyee->entry);
1267 kmutex_unlock(&g_smscore_deviceslock);
1269 kmutex_lock(&g_smscore_registrylock);
1270 while (!list_empty(&g_smscore_registry)) {
1271 struct smscore_registry_entry_t *entry =
1272 (struct smscore_registry_entry_t *)
1273 g_smscore_registry.next;
1275 list_del(&entry->entry);
1278 kmutex_unlock(&g_smscore_registrylock);
1280 /* DVB UnRegister */
1281 smsdvb_unregister();
1283 /* Unregister USB */
1284 smsusb_unregister();
1289 module_init(smscore_module_init);
1290 module_exit(smscore_module_exit);
1292 MODULE_DESCRIPTION("smscore");
1293 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1294 MODULE_LICENSE("GPL");