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 struct smscore_device_notifyee_t {
41 struct list_head entry;
45 struct smscore_idlist_t {
46 struct list_head entry;
51 struct smscore_client_t {
52 struct list_head entry;
53 struct smscore_device_t *coredev;
55 struct list_head idlist;
56 onresponse_t onresponse_handler;
57 onremove_t onremove_handler;
60 struct smscore_device_t {
61 struct list_head entry;
63 struct list_head clients;
64 struct list_head subclients;
65 spinlock_t clientslock;
67 struct list_head buffers;
68 spinlock_t bufferslock;
72 int common_buffer_size;
73 dma_addr_t common_buffer_phys;
76 struct device *device;
79 unsigned long device_flags;
81 setmode_t setmode_handler;
82 detectmode_t detectmode_handler;
83 sendrequest_t sendrequest_handler;
84 preload_t preload_handler;
85 postload_t postload_handler;
87 int mode, modes_supported;
89 struct completion version_ex_done, data_download_done, trigger_done;
90 struct completion init_device_done, reload_start_done, resume_done;
95 void smscore_set_board_id(struct smscore_device_t *core, int id)
100 int smscore_get_board_id(struct smscore_device_t *core)
102 return core->board_id;
105 struct smscore_registry_entry_t {
106 struct list_head entry;
109 enum sms_device_type_st type;
112 struct list_head g_smscore_notifyees;
113 struct list_head g_smscore_devices;
114 kmutex_t g_smscore_deviceslock;
116 struct list_head g_smscore_registry;
117 kmutex_t g_smscore_registrylock;
119 static int default_mode = 4;
121 module_param(default_mode, int, 0644);
122 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
124 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
126 struct smscore_registry_entry_t *entry;
127 struct list_head *next;
129 kmutex_lock(&g_smscore_registrylock);
130 for (next = g_smscore_registry.next;
131 next != &g_smscore_registry;
133 entry = (struct smscore_registry_entry_t *) next;
134 if (!strcmp(entry->devpath, devpath)) {
135 kmutex_unlock(&g_smscore_registrylock);
139 entry = (struct smscore_registry_entry_t *)
140 kmalloc(sizeof(struct smscore_registry_entry_t),
143 entry->mode = default_mode;
144 strcpy(entry->devpath, devpath);
145 list_add(&entry->entry, &g_smscore_registry);
147 sms_err("failed to create smscore_registry.");
148 kmutex_unlock(&g_smscore_registrylock);
152 int smscore_registry_getmode(char *devpath)
154 struct smscore_registry_entry_t *entry;
156 entry = smscore_find_registry(devpath);
160 sms_err("No registry found.");
165 enum sms_device_type_st smscore_registry_gettype(char *devpath)
167 struct smscore_registry_entry_t *entry;
169 entry = smscore_find_registry(devpath);
173 sms_err("No registry found.");
178 void smscore_registry_setmode(char *devpath, int mode)
180 struct smscore_registry_entry_t *entry;
182 entry = smscore_find_registry(devpath);
186 sms_err("No registry found.");
189 void smscore_registry_settype(char *devpath, enum sms_device_type_st type)
191 struct smscore_registry_entry_t *entry;
193 entry = smscore_find_registry(devpath);
197 sms_err("No registry found.");
201 void list_add_locked(struct list_head *new, struct list_head *head,
206 spin_lock_irqsave(lock, flags);
210 spin_unlock_irqrestore(lock, flags);
214 * register a client callback that called when device plugged in/unplugged
215 * NOTE: if devices exist callback is called immediately for each device
217 * @param hotplug callback
219 * @return 0 on success, <0 on error.
221 int smscore_register_hotplug(hotplug_t hotplug)
223 struct smscore_device_notifyee_t *notifyee;
224 struct list_head *next, *first;
227 kmutex_lock(&g_smscore_deviceslock);
229 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
232 /* now notify callback about existing devices */
233 first = &g_smscore_devices;
234 for (next = first->next;
235 next != first && !rc;
237 struct smscore_device_t *coredev =
238 (struct smscore_device_t *) next;
239 rc = hotplug(coredev, coredev->device, 1);
243 notifyee->hotplug = hotplug;
244 list_add(¬ifyee->entry, &g_smscore_notifyees);
250 kmutex_unlock(&g_smscore_deviceslock);
256 * unregister a client callback that called when device plugged in/unplugged
258 * @param hotplug callback
261 void smscore_unregister_hotplug(hotplug_t hotplug)
263 struct list_head *next, *first;
265 kmutex_lock(&g_smscore_deviceslock);
267 first = &g_smscore_notifyees;
269 for (next = first->next; next != first;) {
270 struct smscore_device_notifyee_t *notifyee =
271 (struct smscore_device_notifyee_t *) next;
274 if (notifyee->hotplug == hotplug) {
275 list_del(¬ifyee->entry);
280 kmutex_unlock(&g_smscore_deviceslock);
283 void smscore_notify_clients(struct smscore_device_t *coredev)
285 struct smscore_client_t *client;
287 /* the client must call smscore_unregister_client from remove handler */
288 while (!list_empty(&coredev->clients)) {
289 client = (struct smscore_client_t *) coredev->clients.next;
290 client->onremove_handler(client->context);
294 int smscore_notify_callbacks(struct smscore_device_t *coredev,
295 struct device *device, int arrival)
297 struct list_head *next, *first;
300 /* note: must be called under g_deviceslock */
302 first = &g_smscore_notifyees;
304 for (next = first->next; next != first; next = next->next) {
305 rc = ((struct smscore_device_notifyee_t *) next)->
306 hotplug(coredev, device, arrival);
314 struct smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
315 dma_addr_t common_buffer_phys)
317 struct smscore_buffer_t *cb =
318 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
320 sms_info("kmalloc(...) failed");
325 cb->offset_in_common = buffer - (u8 *) common_buffer;
326 cb->phys = common_buffer_phys + cb->offset_in_common;
332 * creates coredev object for a device, prepares buffers,
333 * creates buffer mappings, notifies registered hotplugs about new device.
335 * @param params device pointer to struct with device specific parameters
337 * @param coredev pointer to a value that receives created coredev object
339 * @return 0 on success, <0 on error.
341 int smscore_register_device(struct smsdevice_params_t *params,
342 struct smscore_device_t **coredev)
344 struct smscore_device_t *dev;
347 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
349 sms_info("kzalloc(...) failed");
353 /* init list entry so it could be safe in smscore_unregister_device */
354 INIT_LIST_HEAD(&dev->entry);
357 INIT_LIST_HEAD(&dev->clients);
358 INIT_LIST_HEAD(&dev->buffers);
361 spin_lock_init(&dev->clientslock);
362 spin_lock_init(&dev->bufferslock);
364 /* init completion events */
365 init_completion(&dev->version_ex_done);
366 init_completion(&dev->data_download_done);
367 init_completion(&dev->trigger_done);
368 init_completion(&dev->init_device_done);
369 init_completion(&dev->reload_start_done);
370 init_completion(&dev->resume_done);
372 /* alloc common buffer */
373 dev->common_buffer_size = params->buffer_size * params->num_buffers;
374 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
375 &dev->common_buffer_phys,
376 GFP_KERNEL | GFP_DMA);
377 if (!dev->common_buffer) {
378 smscore_unregister_device(dev);
382 /* prepare dma buffers */
383 for (buffer = dev->common_buffer;
384 dev->num_buffers < params->num_buffers;
385 dev->num_buffers++, buffer += params->buffer_size) {
386 struct smscore_buffer_t *cb =
387 smscore_createbuffer(buffer, dev->common_buffer,
388 dev->common_buffer_phys);
390 smscore_unregister_device(dev);
394 smscore_putbuffer(dev, cb);
397 sms_info("allocated %d buffers", dev->num_buffers);
399 dev->mode = DEVICE_MODE_NONE;
400 dev->context = params->context;
401 dev->device = params->device;
402 dev->setmode_handler = params->setmode_handler;
403 dev->detectmode_handler = params->detectmode_handler;
404 dev->sendrequest_handler = params->sendrequest_handler;
405 dev->preload_handler = params->preload_handler;
406 dev->postload_handler = params->postload_handler;
408 dev->device_flags = params->flags;
409 strcpy(dev->devpath, params->devpath);
411 smscore_registry_settype(dev->devpath, params->device_type);
413 /* add device to devices list */
414 kmutex_lock(&g_smscore_deviceslock);
415 list_add(&dev->entry, &g_smscore_devices);
416 kmutex_unlock(&g_smscore_deviceslock);
420 sms_info("device %p created", dev);
426 * sets initial device mode and notifies client hotplugs that device is ready
428 * @param coredev pointer to a coredev object returned by
429 * smscore_register_device
431 * @return 0 on success, <0 on error.
433 int smscore_start_device(struct smscore_device_t *coredev)
435 int rc = smscore_set_device_mode(
436 coredev, smscore_registry_getmode(coredev->devpath));
438 sms_info("set device mode faile , rc %d", rc);
442 kmutex_lock(&g_smscore_deviceslock);
444 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
446 sms_info("device %p started, rc %d", coredev, rc);
448 kmutex_unlock(&g_smscore_deviceslock);
453 int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer,
454 size_t size, struct completion *completion)
456 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
458 sms_info("sendrequest returned error %d", rc);
462 return wait_for_completion_timeout(completion,
463 msecs_to_jiffies(10000)) ?
467 int smscore_load_firmware_family2(struct smscore_device_t *coredev,
468 void *buffer, size_t size)
470 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
471 struct SmsMsgHdr_ST *msg;
472 u32 mem_address = firmware->StartAddress;
473 u8 *payload = firmware->Payload;
476 sms_info("loading FW to addr 0x%x size %d",
477 mem_address, firmware->Length);
478 if (coredev->preload_handler) {
479 rc = coredev->preload_handler(coredev->context);
484 /* PAGE_SIZE buffer shall be enough and dma aligned */
485 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
489 if (coredev->mode != DEVICE_MODE_NONE) {
490 sms_debug("sending reload command.");
491 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
492 sizeof(struct SmsMsgHdr_ST));
493 rc = smscore_sendrequest_and_wait(coredev, msg,
495 &coredev->reload_start_done);
496 mem_address = *(u32 *) &payload[20];
499 while (size && rc >= 0) {
500 struct SmsDataDownload_ST *DataMsg =
501 (struct SmsDataDownload_ST *) msg;
502 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
504 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
505 (u16)(sizeof(struct SmsMsgHdr_ST) +
506 sizeof(u32) + payload_size));
508 DataMsg->MemAddr = mem_address;
509 memcpy(DataMsg->Payload, payload, payload_size);
511 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
512 (coredev->mode == DEVICE_MODE_NONE))
513 rc = coredev->sendrequest_handler(
514 coredev->context, DataMsg,
515 DataMsg->xMsgHeader.msgLength);
517 rc = smscore_sendrequest_and_wait(
519 DataMsg->xMsgHeader.msgLength,
520 &coredev->data_download_done);
522 payload += payload_size;
523 size -= payload_size;
524 mem_address += payload_size;
528 if (coredev->mode == DEVICE_MODE_NONE) {
529 struct SmsMsgData_ST *TriggerMsg =
530 (struct SmsMsgData_ST *) msg;
532 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
533 sizeof(struct SmsMsgHdr_ST) +
536 TriggerMsg->msgData[0] = firmware->StartAddress;
538 TriggerMsg->msgData[1] = 5; /* Priority */
539 TriggerMsg->msgData[2] = 0x200; /* Stack size */
540 TriggerMsg->msgData[3] = 0; /* Parameter */
541 TriggerMsg->msgData[4] = 4; /* Task ID */
543 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
544 rc = coredev->sendrequest_handler(
545 coredev->context, TriggerMsg,
546 TriggerMsg->xMsgHeader.msgLength);
549 rc = smscore_sendrequest_and_wait(
551 TriggerMsg->xMsgHeader.msgLength,
552 &coredev->trigger_done);
554 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
555 sizeof(struct SmsMsgHdr_ST));
557 rc = coredev->sendrequest_handler(coredev->context,
558 msg, msg->msgLength);
563 sms_debug("rc=%d, postload=%p ", rc,
564 coredev->postload_handler);
568 return ((rc >= 0) && coredev->postload_handler) ?
569 coredev->postload_handler(coredev->context) :
574 * loads specified firmware into a buffer and calls device loadfirmware_handler
576 * @param coredev pointer to a coredev object returned by
577 * smscore_register_device
578 * @param filename null-terminated string specifies firmware file name
579 * @param loadfirmware_handler device handler that loads firmware
581 * @return 0 on success, <0 on error.
583 int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
585 loadfirmware_t loadfirmware_handler)
588 const struct firmware *fw;
591 if (loadfirmware_handler == NULL && !(coredev->device_flags &
595 rc = request_firmware(&fw, filename, coredev->device);
597 sms_info("failed to open \"%s\"", filename);
600 sms_info("read FW %s, size=%d\"", filename, fw->size);
601 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
602 GFP_KERNEL | GFP_DMA);
604 memcpy(fw_buffer, fw->data, fw->size);
606 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
607 smscore_load_firmware_family2(coredev,
610 loadfirmware_handler(coredev->context,
611 fw_buffer, fw->size);
615 sms_info("failed to allocate firmware buffer");
619 release_firmware(fw);
624 int smscore_load_firmware_from_buffer(struct smscore_device_t *coredev,
625 u8 *buffer, int size, int new_mode)
627 sms_err("feature not yet implemented.");
632 * notifies all clients registered with the device, notifies hotplugs,
633 * frees all buffers and coredev object
635 * @param coredev pointer to a coredev object returned by
636 * smscore_register_device
638 * @return 0 on success, <0 on error.
640 void smscore_unregister_device(struct smscore_device_t *coredev)
642 struct smscore_buffer_t *cb;
646 kmutex_lock(&g_smscore_deviceslock);
648 smscore_notify_clients(coredev);
649 smscore_notify_callbacks(coredev, NULL, 0);
651 /* at this point all buffers should be back
652 * onresponse must no longer be called */
655 while ((cb = smscore_getbuffer(coredev))) {
659 if (num_buffers == coredev->num_buffers)
662 sms_info("exiting although "
663 "not all buffers released.");
667 sms_info("waiting for %d buffer(s)",
668 coredev->num_buffers - num_buffers);
672 sms_info("freed %d buffers", num_buffers);
674 if (coredev->common_buffer)
675 dma_free_coherent(NULL, coredev->common_buffer_size,
676 coredev->common_buffer,
677 coredev->common_buffer_phys);
679 list_del(&coredev->entry);
682 kmutex_unlock(&g_smscore_deviceslock);
684 sms_info("device %p destroyed", coredev);
687 int smscore_detect_mode(struct smscore_device_t *coredev)
689 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
690 GFP_KERNEL | GFP_DMA);
691 struct SmsMsgHdr_ST *msg =
692 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
698 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
699 sizeof(struct SmsMsgHdr_ST));
701 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
702 &coredev->version_ex_done);
704 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
706 if (wait_for_completion_timeout(&coredev->resume_done,
707 msecs_to_jiffies(5000))) {
708 rc = smscore_sendrequest_and_wait(
709 coredev, msg, msg->msgLength,
710 &coredev->version_ex_done);
712 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
713 "second try, rc %d", rc);
723 char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
724 /*Stellar NOVA A0 Nova B0 VEGA*/
726 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
728 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
730 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
732 {"none", "none", "none", "none"},
734 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
736 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
738 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
740 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
745 * calls device handler to change mode of operation
746 * NOTE: stellar/usb may disconnect when changing mode
748 * @param coredev pointer to a coredev object returned by
749 * smscore_register_device
750 * @param mode requested mode of operation
752 * @return 0 on success, <0 on error.
754 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
758 enum sms_device_type_st type;
760 sms_debug("set device mode to %d", mode);
761 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
762 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
763 sms_err("invalid mode specified %d", mode);
767 smscore_registry_setmode(coredev->devpath, mode);
769 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
770 rc = smscore_detect_mode(coredev);
772 sms_err("mode detect failed %d", rc);
777 if (coredev->mode == mode) {
778 sms_info("device mode %d already set", mode);
782 if (!(coredev->modes_supported & (1 << mode))) {
783 type = smscore_registry_gettype(coredev->devpath);
784 rc = smscore_load_firmware_from_file(
785 coredev, smscore_fw_lkup[mode][type], NULL);
787 sms_err("load firmware failed %d", rc);
791 sms_info("mode %d supported by running "
794 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
795 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
797 struct SmsMsgData_ST *msg =
798 (struct SmsMsgData_ST *)
799 SMS_ALIGN_ADDRESS(buffer);
801 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
802 sizeof(struct SmsMsgData_ST));
803 msg->msgData[0] = mode;
805 rc = smscore_sendrequest_and_wait(
806 coredev, msg, msg->xMsgHeader.msgLength,
807 &coredev->init_device_done);
811 sms_err("Could not allocate buffer for "
812 "init device message.");
816 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
817 sms_err("invalid mode specified %d", mode);
821 smscore_registry_setmode(coredev->devpath, mode);
823 if (coredev->detectmode_handler)
824 coredev->detectmode_handler(coredev->context,
827 if (coredev->mode != mode && coredev->setmode_handler)
828 rc = coredev->setmode_handler(coredev->context, mode);
832 coredev->mode = mode;
833 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
837 sms_err("return error code %d.", rc);
842 * calls device handler to get current mode of operation
844 * @param coredev pointer to a coredev object returned by
845 * smscore_register_device
847 * @return current mode
849 int smscore_get_device_mode(struct smscore_device_t *coredev)
851 return coredev->mode;
855 * find client by response id & type within the clients list.
856 * return client handle or NULL.
858 * @param coredev pointer to a coredev object returned by
859 * smscore_register_device
860 * @param data_type client data type (SMS_DONT_CARE for all types)
861 * @param id client id (SMS_DONT_CARE for all id)
864 struct smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
865 int data_type, int id)
867 struct smscore_client_t *client = NULL;
868 struct list_head *next, *first;
870 struct list_head *firstid, *nextid;
873 spin_lock_irqsave(&coredev->clientslock, flags);
874 first = &coredev->clients;
875 for (next = first->next;
876 (next != first) && !client;
878 firstid = &((struct smscore_client_t *)next)->idlist;
879 for (nextid = firstid->next;
881 nextid = nextid->next) {
882 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
883 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
884 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
885 client = (struct smscore_client_t *) next;
890 spin_unlock_irqrestore(&coredev->clientslock, flags);
895 * find client by response id/type, call clients onresponse handler
896 * return buffer to pool on error
898 * @param coredev pointer to a coredev object returned by
899 * smscore_register_device
900 * @param cb pointer to response buffer descriptor
903 void smscore_onresponse(struct smscore_device_t *coredev,
904 struct smscore_buffer_t *cb)
906 struct SmsMsgHdr_ST *phdr =
907 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
908 struct smscore_client_t *client =
909 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
912 static unsigned long last_sample_time; /* = 0; */
913 static int data_total; /* = 0; */
914 unsigned long time_now = jiffies_to_msecs(jiffies);
916 if (!last_sample_time)
917 last_sample_time = time_now;
919 if (time_now - last_sample_time > 10000) {
920 sms_debug("\ndata rate %d bytes/secs",
921 (int)((data_total * 1000) /
922 (time_now - last_sample_time)));
924 last_sample_time = time_now;
928 data_total += cb->size;
929 /* If no client registered for type & id,
930 * check for control client where type is not registered */
932 rc = client->onresponse_handler(client->context, cb);
935 switch (phdr->msgType) {
936 case MSG_SMS_GET_VERSION_EX_RES:
938 struct SmsVersionRes_ST *ver =
939 (struct SmsVersionRes_ST *) phdr;
940 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
941 "id %d prots 0x%x ver %d.%d",
942 ver->FirmwareId, ver->SupportedProtocols,
943 ver->RomVersionMajor, ver->RomVersionMinor);
945 coredev->mode = ver->FirmwareId == 255 ?
946 DEVICE_MODE_NONE : ver->FirmwareId;
947 coredev->modes_supported = ver->SupportedProtocols;
949 complete(&coredev->version_ex_done);
952 case MSG_SMS_INIT_DEVICE_RES:
953 sms_debug("MSG_SMS_INIT_DEVICE_RES");
954 complete(&coredev->init_device_done);
956 case MSG_SW_RELOAD_START_RES:
957 sms_debug("MSG_SW_RELOAD_START_RES");
958 complete(&coredev->reload_start_done);
960 case MSG_SMS_DATA_DOWNLOAD_RES:
961 complete(&coredev->data_download_done);
963 case MSG_SW_RELOAD_EXEC_RES:
964 sms_debug("MSG_SW_RELOAD_EXEC_RES");
966 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
967 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
968 complete(&coredev->trigger_done);
970 case MSG_SMS_SLEEP_RESUME_COMP_IND:
971 complete(&coredev->resume_done);
976 smscore_putbuffer(coredev, cb);
981 * return pointer to next free buffer descriptor from core pool
983 * @param coredev pointer to a coredev object returned by
984 * smscore_register_device
986 * @return pointer to descriptor on success, NULL on error.
988 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
990 struct smscore_buffer_t *cb = NULL;
993 spin_lock_irqsave(&coredev->bufferslock, flags);
995 if (!list_empty(&coredev->buffers)) {
996 cb = (struct smscore_buffer_t *) coredev->buffers.next;
997 list_del(&cb->entry);
1000 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1006 * return buffer descriptor to a pool
1008 * @param coredev pointer to a coredev object returned by
1009 * smscore_register_device
1010 * @param cb pointer buffer descriptor
1013 void smscore_putbuffer(struct smscore_device_t *coredev,
1014 struct smscore_buffer_t *cb)
1016 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1019 int smscore_validate_client(struct smscore_device_t *coredev,
1020 struct smscore_client_t *client,
1021 int data_type, int id)
1023 struct smscore_idlist_t *listentry;
1024 struct smscore_client_t *registered_client;
1027 sms_err("bad parameter.");
1030 registered_client = smscore_find_client(coredev, data_type, id);
1031 if (registered_client == client)
1034 if (registered_client) {
1035 sms_err("The msg ID already registered to another client.");
1038 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1040 sms_err("Can't allocate memory for client id.");
1044 listentry->data_type = data_type;
1045 list_add_locked(&listentry->entry, &client->idlist,
1046 &coredev->clientslock);
1051 * creates smsclient object, check that id is taken by another client
1053 * @param coredev pointer to a coredev object from clients hotplug
1054 * @param initial_id all messages with this id would be sent to this client
1055 * @param data_type all messages of this type would be sent to this client
1056 * @param onresponse_handler client handler that is called to
1057 * process incoming messages
1058 * @param onremove_handler client handler that is called when device is removed
1059 * @param context client-specific context
1060 * @param client pointer to a value that receives created smsclient object
1062 * @return 0 on success, <0 on error.
1064 int smscore_register_client(struct smscore_device_t *coredev,
1065 struct smsclient_params_t *params,
1066 struct smscore_client_t **client)
1068 struct smscore_client_t *newclient;
1069 /* check that no other channel with same parameters exists */
1070 if (smscore_find_client(coredev, params->data_type,
1071 params->initial_id)) {
1072 sms_err("Client already exist.");
1076 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1078 sms_err("Failed to allocate memory for client.");
1082 INIT_LIST_HEAD(&newclient->idlist);
1083 newclient->coredev = coredev;
1084 newclient->onresponse_handler = params->onresponse_handler;
1085 newclient->onremove_handler = params->onremove_handler;
1086 newclient->context = params->context;
1087 list_add_locked(&newclient->entry, &coredev->clients,
1088 &coredev->clientslock);
1089 smscore_validate_client(coredev, newclient, params->data_type,
1090 params->initial_id);
1091 *client = newclient;
1092 sms_debug("%p %d %d", params->context, params->data_type,
1093 params->initial_id);
1099 * frees smsclient object and all subclients associated with it
1101 * @param client pointer to smsclient object returned by
1102 * smscore_register_client
1105 void smscore_unregister_client(struct smscore_client_t *client)
1107 struct smscore_device_t *coredev = client->coredev;
1108 unsigned long flags;
1110 spin_lock_irqsave(&coredev->clientslock, flags);
1113 while (!list_empty(&client->idlist)) {
1114 struct smscore_idlist_t *identry =
1115 (struct smscore_idlist_t *) client->idlist.next;
1116 list_del(&identry->entry);
1120 sms_info("%p", client->context);
1122 list_del(&client->entry);
1125 spin_unlock_irqrestore(&coredev->clientslock, flags);
1129 * verifies that source id is not taken by another client,
1130 * calls device handler to send requests to the device
1132 * @param client pointer to smsclient object returned by
1133 * smscore_register_client
1134 * @param buffer pointer to a request buffer
1135 * @param size size (in bytes) of request buffer
1137 * @return 0 on success, <0 on error.
1139 int smsclient_sendrequest(struct smscore_client_t *client,
1140 void *buffer, size_t size)
1142 struct smscore_device_t *coredev;
1143 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1146 if (client == NULL) {
1147 sms_err("Got NULL client");
1151 coredev = client->coredev;
1153 /* check that no other channel with same id exists */
1154 if (coredev == NULL) {
1155 sms_err("Got NULL coredev");
1159 rc = smscore_validate_client(client->coredev, client, 0,
1164 return coredev->sendrequest_handler(coredev->context, buffer, size);
1168 * return the size of large (common) buffer
1170 * @param coredev pointer to a coredev object from clients hotplug
1172 * @return size (in bytes) of the buffer
1174 int smscore_get_common_buffer_size(struct smscore_device_t *coredev)
1176 return coredev->common_buffer_size;
1180 * maps common buffer (if supported by platform)
1182 * @param coredev pointer to a coredev object from clients hotplug
1183 * @param vma pointer to vma struct from mmap handler
1185 * @return 0 on success, <0 on error.
1187 int smscore_map_common_buffer(struct smscore_device_t *coredev,
1188 struct vm_area_struct *vma)
1190 unsigned long end = vma->vm_end,
1191 start = vma->vm_start,
1192 size = PAGE_ALIGN(coredev->common_buffer_size);
1194 if (!(vma->vm_flags & (VM_READ | VM_SHARED)) ||
1195 (vma->vm_flags & VM_WRITE)) {
1196 sms_err("invalid vm flags");
1200 if ((end - start) != size) {
1201 sms_err("invalid size %d expected %d",
1202 (int)(end - start), (int) size);
1206 if (remap_pfn_range(vma, start,
1207 coredev->common_buffer_phys >> PAGE_SHIFT,
1208 size, pgprot_noncached(vma->vm_page_prot))) {
1209 sms_err("remap_page_range failed");
1216 int smscore_module_init(void)
1220 INIT_LIST_HEAD(&g_smscore_notifyees);
1221 INIT_LIST_HEAD(&g_smscore_devices);
1222 kmutex_init(&g_smscore_deviceslock);
1224 INIT_LIST_HEAD(&g_smscore_registry);
1225 kmutex_init(&g_smscore_registrylock);
1228 rc = smsusb_register();
1231 rc = smsdvb_register();
1233 sms_debug("rc %d", rc);
1238 void smscore_module_exit(void)
1241 kmutex_lock(&g_smscore_deviceslock);
1242 while (!list_empty(&g_smscore_notifyees)) {
1243 struct smscore_device_notifyee_t *notifyee =
1244 (struct smscore_device_notifyee_t *)
1245 g_smscore_notifyees.next;
1247 list_del(¬ifyee->entry);
1250 kmutex_unlock(&g_smscore_deviceslock);
1252 kmutex_lock(&g_smscore_registrylock);
1253 while (!list_empty(&g_smscore_registry)) {
1254 struct smscore_registry_entry_t *entry =
1255 (struct smscore_registry_entry_t *)
1256 g_smscore_registry.next;
1258 list_del(&entry->entry);
1261 kmutex_unlock(&g_smscore_registrylock);
1263 /* DVB UnRegister */
1264 smsdvb_unregister();
1266 /* Unregister USB */
1267 smsusb_unregister();
1272 module_init(smscore_module_init);
1273 module_exit(smscore_module_exit);
1275 MODULE_DESCRIPTION("smscore");
1276 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1277 MODULE_LICENSE("GPL");