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;
96 void smscore_set_board_id(struct smscore_device_t *core, int id)
101 int smscore_get_board_id(struct smscore_device_t *core)
103 return core->board_id;
106 struct smscore_registry_entry_t {
107 struct list_head entry;
110 enum sms_device_type_st type;
113 static struct list_head g_smscore_notifyees;
114 static struct list_head g_smscore_devices;
115 static struct mutex g_smscore_deviceslock;
117 static struct list_head g_smscore_registry;
118 static struct mutex g_smscore_registrylock;
120 static int default_mode = 4;
122 module_param(default_mode, int, 0644);
123 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
125 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
127 struct smscore_registry_entry_t *entry;
128 struct list_head *next;
130 kmutex_lock(&g_smscore_registrylock);
131 for (next = g_smscore_registry.next;
132 next != &g_smscore_registry;
134 entry = (struct smscore_registry_entry_t *) next;
135 if (!strcmp(entry->devpath, devpath)) {
136 kmutex_unlock(&g_smscore_registrylock);
140 entry = (struct smscore_registry_entry_t *)
141 kmalloc(sizeof(struct smscore_registry_entry_t),
144 entry->mode = default_mode;
145 strcpy(entry->devpath, devpath);
146 list_add(&entry->entry, &g_smscore_registry);
148 sms_err("failed to create smscore_registry.");
149 kmutex_unlock(&g_smscore_registrylock);
153 int smscore_registry_getmode(char *devpath)
155 struct smscore_registry_entry_t *entry;
157 entry = smscore_find_registry(devpath);
161 sms_err("No registry found.");
166 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
168 struct smscore_registry_entry_t *entry;
170 entry = smscore_find_registry(devpath);
174 sms_err("No registry found.");
179 void smscore_registry_setmode(char *devpath, int mode)
181 struct smscore_registry_entry_t *entry;
183 entry = smscore_find_registry(devpath);
187 sms_err("No registry found.");
190 static void smscore_registry_settype(char *devpath,
191 enum sms_device_type_st type)
193 struct smscore_registry_entry_t *entry;
195 entry = smscore_find_registry(devpath);
199 sms_err("No registry found.");
203 static void list_add_locked(struct list_head *new, struct list_head *head,
208 spin_lock_irqsave(lock, flags);
212 spin_unlock_irqrestore(lock, flags);
216 * register a client callback that called when device plugged in/unplugged
217 * NOTE: if devices exist callback is called immediately for each device
219 * @param hotplug callback
221 * @return 0 on success, <0 on error.
223 int smscore_register_hotplug(hotplug_t hotplug)
225 struct smscore_device_notifyee_t *notifyee;
226 struct list_head *next, *first;
229 kmutex_lock(&g_smscore_deviceslock);
231 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
234 /* now notify callback about existing devices */
235 first = &g_smscore_devices;
236 for (next = first->next;
237 next != first && !rc;
239 struct smscore_device_t *coredev =
240 (struct smscore_device_t *) next;
241 rc = hotplug(coredev, coredev->device, 1);
245 notifyee->hotplug = hotplug;
246 list_add(¬ifyee->entry, &g_smscore_notifyees);
252 kmutex_unlock(&g_smscore_deviceslock);
258 * unregister a client callback that called when device plugged in/unplugged
260 * @param hotplug callback
263 void smscore_unregister_hotplug(hotplug_t hotplug)
265 struct list_head *next, *first;
267 kmutex_lock(&g_smscore_deviceslock);
269 first = &g_smscore_notifyees;
271 for (next = first->next; next != first;) {
272 struct smscore_device_notifyee_t *notifyee =
273 (struct smscore_device_notifyee_t *) next;
276 if (notifyee->hotplug == hotplug) {
277 list_del(¬ifyee->entry);
282 kmutex_unlock(&g_smscore_deviceslock);
285 static void smscore_notify_clients(struct smscore_device_t *coredev)
287 struct smscore_client_t *client;
289 /* the client must call smscore_unregister_client from remove handler */
290 while (!list_empty(&coredev->clients)) {
291 client = (struct smscore_client_t *) coredev->clients.next;
292 client->onremove_handler(client->context);
296 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
297 struct device *device, int arrival)
299 struct list_head *next, *first;
302 /* note: must be called under g_deviceslock */
304 first = &g_smscore_notifyees;
306 for (next = first->next; next != first; next = next->next) {
307 rc = ((struct smscore_device_notifyee_t *) next)->
308 hotplug(coredev, device, arrival);
317 smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
318 dma_addr_t common_buffer_phys)
320 struct smscore_buffer_t *cb =
321 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
323 sms_info("kmalloc(...) failed");
328 cb->offset_in_common = buffer - (u8 *) common_buffer;
329 cb->phys = common_buffer_phys + cb->offset_in_common;
335 * creates coredev object for a device, prepares buffers,
336 * creates buffer mappings, notifies registered hotplugs about new device.
338 * @param params device pointer to struct with device specific parameters
340 * @param coredev pointer to a value that receives created coredev object
342 * @return 0 on success, <0 on error.
344 int smscore_register_device(struct smsdevice_params_t *params,
345 struct smscore_device_t **coredev)
347 struct smscore_device_t *dev;
350 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
352 sms_info("kzalloc(...) failed");
356 /* init list entry so it could be safe in smscore_unregister_device */
357 INIT_LIST_HEAD(&dev->entry);
360 INIT_LIST_HEAD(&dev->clients);
361 INIT_LIST_HEAD(&dev->buffers);
364 spin_lock_init(&dev->clientslock);
365 spin_lock_init(&dev->bufferslock);
367 /* init completion events */
368 init_completion(&dev->version_ex_done);
369 init_completion(&dev->data_download_done);
370 init_completion(&dev->trigger_done);
371 init_completion(&dev->init_device_done);
372 init_completion(&dev->reload_start_done);
373 init_completion(&dev->resume_done);
375 /* alloc common buffer */
376 dev->common_buffer_size = params->buffer_size * params->num_buffers;
377 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
378 &dev->common_buffer_phys,
379 GFP_KERNEL | GFP_DMA);
380 if (!dev->common_buffer) {
381 smscore_unregister_device(dev);
385 /* prepare dma buffers */
386 for (buffer = dev->common_buffer;
387 dev->num_buffers < params->num_buffers;
388 dev->num_buffers++, buffer += params->buffer_size) {
389 struct smscore_buffer_t *cb =
390 smscore_createbuffer(buffer, dev->common_buffer,
391 dev->common_buffer_phys);
393 smscore_unregister_device(dev);
397 smscore_putbuffer(dev, cb);
400 sms_info("allocated %d buffers", dev->num_buffers);
402 dev->mode = DEVICE_MODE_NONE;
403 dev->context = params->context;
404 dev->device = params->device;
405 dev->setmode_handler = params->setmode_handler;
406 dev->detectmode_handler = params->detectmode_handler;
407 dev->sendrequest_handler = params->sendrequest_handler;
408 dev->preload_handler = params->preload_handler;
409 dev->postload_handler = params->postload_handler;
411 dev->device_flags = params->flags;
412 strcpy(dev->devpath, params->devpath);
414 smscore_registry_settype(dev->devpath, params->device_type);
416 /* add device to devices list */
417 kmutex_lock(&g_smscore_deviceslock);
418 list_add(&dev->entry, &g_smscore_devices);
419 kmutex_unlock(&g_smscore_deviceslock);
423 sms_info("device %p created", dev);
429 * sets initial device mode and notifies client hotplugs that device is ready
431 * @param coredev pointer to a coredev object returned by
432 * smscore_register_device
434 * @return 0 on success, <0 on error.
436 int smscore_start_device(struct smscore_device_t *coredev)
438 int rc = smscore_set_device_mode(
439 coredev, smscore_registry_getmode(coredev->devpath));
441 sms_info("set device mode faile , rc %d", rc);
445 kmutex_lock(&g_smscore_deviceslock);
447 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
449 sms_info("device %p started, rc %d", coredev, rc);
451 kmutex_unlock(&g_smscore_deviceslock);
456 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
457 void *buffer, size_t size,
458 struct completion *completion)
460 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
462 sms_info("sendrequest returned error %d", rc);
466 return wait_for_completion_timeout(completion,
467 msecs_to_jiffies(10000)) ?
471 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
472 void *buffer, size_t size)
474 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
475 struct SmsMsgHdr_ST *msg;
476 u32 mem_address = firmware->StartAddress;
477 u8 *payload = firmware->Payload;
480 sms_info("loading FW to addr 0x%x size %d",
481 mem_address, firmware->Length);
482 if (coredev->preload_handler) {
483 rc = coredev->preload_handler(coredev->context);
488 /* PAGE_SIZE buffer shall be enough and dma aligned */
489 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
493 if (coredev->mode != DEVICE_MODE_NONE) {
494 sms_debug("sending reload command.");
495 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
496 sizeof(struct SmsMsgHdr_ST));
497 rc = smscore_sendrequest_and_wait(coredev, msg,
499 &coredev->reload_start_done);
500 mem_address = *(u32 *) &payload[20];
503 while (size && rc >= 0) {
504 struct SmsDataDownload_ST *DataMsg =
505 (struct SmsDataDownload_ST *) msg;
506 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
508 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
509 (u16)(sizeof(struct SmsMsgHdr_ST) +
510 sizeof(u32) + payload_size));
512 DataMsg->MemAddr = mem_address;
513 memcpy(DataMsg->Payload, payload, payload_size);
515 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
516 (coredev->mode == DEVICE_MODE_NONE))
517 rc = coredev->sendrequest_handler(
518 coredev->context, DataMsg,
519 DataMsg->xMsgHeader.msgLength);
521 rc = smscore_sendrequest_and_wait(
523 DataMsg->xMsgHeader.msgLength,
524 &coredev->data_download_done);
526 payload += payload_size;
527 size -= payload_size;
528 mem_address += payload_size;
532 if (coredev->mode == DEVICE_MODE_NONE) {
533 struct SmsMsgData_ST *TriggerMsg =
534 (struct SmsMsgData_ST *) msg;
536 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
537 sizeof(struct SmsMsgHdr_ST) +
540 TriggerMsg->msgData[0] = firmware->StartAddress;
542 TriggerMsg->msgData[1] = 5; /* Priority */
543 TriggerMsg->msgData[2] = 0x200; /* Stack size */
544 TriggerMsg->msgData[3] = 0; /* Parameter */
545 TriggerMsg->msgData[4] = 4; /* Task ID */
547 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
548 rc = coredev->sendrequest_handler(
549 coredev->context, TriggerMsg,
550 TriggerMsg->xMsgHeader.msgLength);
553 rc = smscore_sendrequest_and_wait(
555 TriggerMsg->xMsgHeader.msgLength,
556 &coredev->trigger_done);
558 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
559 sizeof(struct SmsMsgHdr_ST));
561 rc = coredev->sendrequest_handler(coredev->context,
562 msg, msg->msgLength);
567 sms_debug("rc=%d, postload=%p ", rc,
568 coredev->postload_handler);
572 return ((rc >= 0) && coredev->postload_handler) ?
573 coredev->postload_handler(coredev->context) :
578 * loads specified firmware into a buffer and calls device loadfirmware_handler
580 * @param coredev pointer to a coredev object returned by
581 * smscore_register_device
582 * @param filename null-terminated string specifies firmware file name
583 * @param loadfirmware_handler device handler that loads firmware
585 * @return 0 on success, <0 on error.
587 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
589 loadfirmware_t loadfirmware_handler)
592 const struct firmware *fw;
595 if (loadfirmware_handler == NULL && !(coredev->device_flags &
599 rc = request_firmware(&fw, filename, coredev->device);
601 sms_info("failed to open \"%s\"", filename);
604 sms_info("read FW %s, size=%zd", filename, fw->size);
605 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
606 GFP_KERNEL | GFP_DMA);
608 memcpy(fw_buffer, fw->data, fw->size);
610 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
611 smscore_load_firmware_family2(coredev,
614 loadfirmware_handler(coredev->context,
615 fw_buffer, fw->size);
619 sms_info("failed to allocate firmware buffer");
623 release_firmware(fw);
629 * notifies all clients registered with the device, notifies hotplugs,
630 * frees all buffers and coredev object
632 * @param coredev pointer to a coredev object returned by
633 * smscore_register_device
635 * @return 0 on success, <0 on error.
637 void smscore_unregister_device(struct smscore_device_t *coredev)
639 struct smscore_buffer_t *cb;
643 kmutex_lock(&g_smscore_deviceslock);
645 smscore_notify_clients(coredev);
646 smscore_notify_callbacks(coredev, NULL, 0);
648 /* at this point all buffers should be back
649 * onresponse must no longer be called */
652 while ((cb = smscore_getbuffer(coredev))) {
656 if (num_buffers == coredev->num_buffers)
659 sms_info("exiting although "
660 "not all buffers released.");
664 sms_info("waiting for %d buffer(s)",
665 coredev->num_buffers - num_buffers);
669 sms_info("freed %d buffers", num_buffers);
671 if (coredev->common_buffer)
672 dma_free_coherent(NULL, coredev->common_buffer_size,
673 coredev->common_buffer,
674 coredev->common_buffer_phys);
676 list_del(&coredev->entry);
679 kmutex_unlock(&g_smscore_deviceslock);
681 sms_info("device %p destroyed", coredev);
684 static int smscore_detect_mode(struct smscore_device_t *coredev)
686 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
687 GFP_KERNEL | GFP_DMA);
688 struct SmsMsgHdr_ST *msg =
689 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
695 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
696 sizeof(struct SmsMsgHdr_ST));
698 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
699 &coredev->version_ex_done);
701 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
703 if (wait_for_completion_timeout(&coredev->resume_done,
704 msecs_to_jiffies(5000))) {
705 rc = smscore_sendrequest_and_wait(
706 coredev, msg, msg->msgLength,
707 &coredev->version_ex_done);
709 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
710 "second try, rc %d", rc);
720 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
721 /*Stellar NOVA A0 Nova B0 VEGA*/
723 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
725 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
727 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
729 {"none", "none", "none", "none"},
731 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
733 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
735 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
737 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
740 static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
741 int mode, enum sms_device_type_st type)
743 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
744 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
748 * calls device handler to change mode of operation
749 * NOTE: stellar/usb may disconnect when changing mode
751 * @param coredev pointer to a coredev object returned by
752 * smscore_register_device
753 * @param mode requested mode of operation
755 * @return 0 on success, <0 on error.
757 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
761 enum sms_device_type_st type;
763 sms_debug("set device mode to %d", mode);
764 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
765 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
766 sms_err("invalid mode specified %d", mode);
770 smscore_registry_setmode(coredev->devpath, mode);
772 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
773 rc = smscore_detect_mode(coredev);
775 sms_err("mode detect failed %d", rc);
780 if (coredev->mode == mode) {
781 sms_info("device mode %d already set", mode);
785 if (!(coredev->modes_supported & (1 << mode))) {
788 type = smscore_registry_gettype(coredev->devpath);
789 fw_filename = sms_get_fw_name(coredev, mode, type);
791 rc = smscore_load_firmware_from_file(coredev,
794 sms_warn("error %d loading firmware: %s, "
795 "trying again with default firmware",
798 /* try again with the default firmware */
799 fw_filename = smscore_fw_lkup[mode][type];
800 rc = smscore_load_firmware_from_file(coredev,
804 sms_warn("error %d loading "
810 sms_log("firmware download success: %s", fw_filename);
812 sms_info("mode %d supported by running "
815 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
816 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
818 struct SmsMsgData_ST *msg =
819 (struct SmsMsgData_ST *)
820 SMS_ALIGN_ADDRESS(buffer);
822 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
823 sizeof(struct SmsMsgData_ST));
824 msg->msgData[0] = mode;
826 rc = smscore_sendrequest_and_wait(
827 coredev, msg, msg->xMsgHeader.msgLength,
828 &coredev->init_device_done);
832 sms_err("Could not allocate buffer for "
833 "init device message.");
837 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
838 sms_err("invalid mode specified %d", mode);
842 smscore_registry_setmode(coredev->devpath, mode);
844 if (coredev->detectmode_handler)
845 coredev->detectmode_handler(coredev->context,
848 if (coredev->mode != mode && coredev->setmode_handler)
849 rc = coredev->setmode_handler(coredev->context, mode);
853 coredev->mode = mode;
854 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
858 sms_err("return error code %d.", rc);
863 * calls device handler to get current mode of operation
865 * @param coredev pointer to a coredev object returned by
866 * smscore_register_device
868 * @return current mode
870 int smscore_get_device_mode(struct smscore_device_t *coredev)
872 return coredev->mode;
876 * find client by response id & type within the clients list.
877 * return client handle or NULL.
879 * @param coredev pointer to a coredev object returned by
880 * smscore_register_device
881 * @param data_type client data type (SMS_DONT_CARE for all types)
882 * @param id client id (SMS_DONT_CARE for all id)
886 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
887 int data_type, int id)
889 struct smscore_client_t *client = NULL;
890 struct list_head *next, *first;
892 struct list_head *firstid, *nextid;
895 spin_lock_irqsave(&coredev->clientslock, flags);
896 first = &coredev->clients;
897 for (next = first->next;
898 (next != first) && !client;
900 firstid = &((struct smscore_client_t *)next)->idlist;
901 for (nextid = firstid->next;
903 nextid = nextid->next) {
904 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
905 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
906 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
907 client = (struct smscore_client_t *) next;
912 spin_unlock_irqrestore(&coredev->clientslock, flags);
917 * find client by response id/type, call clients onresponse handler
918 * return buffer to pool on error
920 * @param coredev pointer to a coredev object returned by
921 * smscore_register_device
922 * @param cb pointer to response buffer descriptor
925 void smscore_onresponse(struct smscore_device_t *coredev,
926 struct smscore_buffer_t *cb)
928 struct SmsMsgHdr_ST *phdr =
929 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
930 struct smscore_client_t *client =
931 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
934 static unsigned long last_sample_time; /* = 0; */
935 static int data_total; /* = 0; */
936 unsigned long time_now = jiffies_to_msecs(jiffies);
938 if (!last_sample_time)
939 last_sample_time = time_now;
941 if (time_now - last_sample_time > 10000) {
942 sms_debug("\ndata rate %d bytes/secs",
943 (int)((data_total * 1000) /
944 (time_now - last_sample_time)));
946 last_sample_time = time_now;
950 data_total += cb->size;
951 /* If no client registered for type & id,
952 * check for control client where type is not registered */
954 rc = client->onresponse_handler(client->context, cb);
957 switch (phdr->msgType) {
958 case MSG_SMS_GET_VERSION_EX_RES:
960 struct SmsVersionRes_ST *ver =
961 (struct SmsVersionRes_ST *) phdr;
962 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
963 "id %d prots 0x%x ver %d.%d",
964 ver->FirmwareId, ver->SupportedProtocols,
965 ver->RomVersionMajor, ver->RomVersionMinor);
967 coredev->mode = ver->FirmwareId == 255 ?
968 DEVICE_MODE_NONE : ver->FirmwareId;
969 coredev->modes_supported = ver->SupportedProtocols;
971 complete(&coredev->version_ex_done);
974 case MSG_SMS_INIT_DEVICE_RES:
975 sms_debug("MSG_SMS_INIT_DEVICE_RES");
976 complete(&coredev->init_device_done);
978 case MSG_SW_RELOAD_START_RES:
979 sms_debug("MSG_SW_RELOAD_START_RES");
980 complete(&coredev->reload_start_done);
982 case MSG_SMS_DATA_DOWNLOAD_RES:
983 complete(&coredev->data_download_done);
985 case MSG_SW_RELOAD_EXEC_RES:
986 sms_debug("MSG_SW_RELOAD_EXEC_RES");
988 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
989 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
990 complete(&coredev->trigger_done);
992 case MSG_SMS_SLEEP_RESUME_COMP_IND:
993 complete(&coredev->resume_done);
998 smscore_putbuffer(coredev, cb);
1003 * return pointer to next free buffer descriptor from core pool
1005 * @param coredev pointer to a coredev object returned by
1006 * smscore_register_device
1008 * @return pointer to descriptor on success, NULL on error.
1010 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1012 struct smscore_buffer_t *cb = NULL;
1013 unsigned long flags;
1015 spin_lock_irqsave(&coredev->bufferslock, flags);
1017 if (!list_empty(&coredev->buffers)) {
1018 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1019 list_del(&cb->entry);
1022 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1028 * return buffer descriptor to a pool
1030 * @param coredev pointer to a coredev object returned by
1031 * smscore_register_device
1032 * @param cb pointer buffer descriptor
1035 void smscore_putbuffer(struct smscore_device_t *coredev,
1036 struct smscore_buffer_t *cb)
1038 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1041 static int smscore_validate_client(struct smscore_device_t *coredev,
1042 struct smscore_client_t *client,
1043 int data_type, int id)
1045 struct smscore_idlist_t *listentry;
1046 struct smscore_client_t *registered_client;
1049 sms_err("bad parameter.");
1052 registered_client = smscore_find_client(coredev, data_type, id);
1053 if (registered_client == client)
1056 if (registered_client) {
1057 sms_err("The msg ID already registered to another client.");
1060 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1062 sms_err("Can't allocate memory for client id.");
1066 listentry->data_type = data_type;
1067 list_add_locked(&listentry->entry, &client->idlist,
1068 &coredev->clientslock);
1073 * creates smsclient object, check that id is taken by another client
1075 * @param coredev pointer to a coredev object from clients hotplug
1076 * @param initial_id all messages with this id would be sent to this client
1077 * @param data_type all messages of this type would be sent to this client
1078 * @param onresponse_handler client handler that is called to
1079 * process incoming messages
1080 * @param onremove_handler client handler that is called when device is removed
1081 * @param context client-specific context
1082 * @param client pointer to a value that receives created smsclient object
1084 * @return 0 on success, <0 on error.
1086 int smscore_register_client(struct smscore_device_t *coredev,
1087 struct smsclient_params_t *params,
1088 struct smscore_client_t **client)
1090 struct smscore_client_t *newclient;
1091 /* check that no other channel with same parameters exists */
1092 if (smscore_find_client(coredev, params->data_type,
1093 params->initial_id)) {
1094 sms_err("Client already exist.");
1098 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1100 sms_err("Failed to allocate memory for client.");
1104 INIT_LIST_HEAD(&newclient->idlist);
1105 newclient->coredev = coredev;
1106 newclient->onresponse_handler = params->onresponse_handler;
1107 newclient->onremove_handler = params->onremove_handler;
1108 newclient->context = params->context;
1109 list_add_locked(&newclient->entry, &coredev->clients,
1110 &coredev->clientslock);
1111 smscore_validate_client(coredev, newclient, params->data_type,
1112 params->initial_id);
1113 *client = newclient;
1114 sms_debug("%p %d %d", params->context, params->data_type,
1115 params->initial_id);
1121 * frees smsclient object and all subclients associated with it
1123 * @param client pointer to smsclient object returned by
1124 * smscore_register_client
1127 void smscore_unregister_client(struct smscore_client_t *client)
1129 struct smscore_device_t *coredev = client->coredev;
1130 unsigned long flags;
1132 spin_lock_irqsave(&coredev->clientslock, flags);
1135 while (!list_empty(&client->idlist)) {
1136 struct smscore_idlist_t *identry =
1137 (struct smscore_idlist_t *) client->idlist.next;
1138 list_del(&identry->entry);
1142 sms_info("%p", client->context);
1144 list_del(&client->entry);
1147 spin_unlock_irqrestore(&coredev->clientslock, flags);
1151 * verifies that source id is not taken by another client,
1152 * calls device handler to send requests to the device
1154 * @param client pointer to smsclient object returned by
1155 * smscore_register_client
1156 * @param buffer pointer to a request buffer
1157 * @param size size (in bytes) of request buffer
1159 * @return 0 on success, <0 on error.
1161 int smsclient_sendrequest(struct smscore_client_t *client,
1162 void *buffer, size_t size)
1164 struct smscore_device_t *coredev;
1165 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1168 if (client == NULL) {
1169 sms_err("Got NULL client");
1173 coredev = client->coredev;
1175 /* check that no other channel with same id exists */
1176 if (coredev == NULL) {
1177 sms_err("Got NULL coredev");
1181 rc = smscore_validate_client(client->coredev, client, 0,
1186 return coredev->sendrequest_handler(coredev->context, buffer, size);
1190 static int __init smscore_module_init(void)
1194 INIT_LIST_HEAD(&g_smscore_notifyees);
1195 INIT_LIST_HEAD(&g_smscore_devices);
1196 kmutex_init(&g_smscore_deviceslock);
1198 INIT_LIST_HEAD(&g_smscore_registry);
1199 kmutex_init(&g_smscore_registrylock);
1202 rc = smsusb_register();
1205 rc = smsdvb_register();
1207 sms_debug("rc %d", rc);
1212 static void __exit smscore_module_exit(void)
1215 kmutex_lock(&g_smscore_deviceslock);
1216 while (!list_empty(&g_smscore_notifyees)) {
1217 struct smscore_device_notifyee_t *notifyee =
1218 (struct smscore_device_notifyee_t *)
1219 g_smscore_notifyees.next;
1221 list_del(¬ifyee->entry);
1224 kmutex_unlock(&g_smscore_deviceslock);
1226 kmutex_lock(&g_smscore_registrylock);
1227 while (!list_empty(&g_smscore_registry)) {
1228 struct smscore_registry_entry_t *entry =
1229 (struct smscore_registry_entry_t *)
1230 g_smscore_registry.next;
1232 list_del(&entry->entry);
1235 kmutex_unlock(&g_smscore_registrylock);
1237 /* DVB UnRegister */
1238 smsdvb_unregister();
1240 /* Unregister USB */
1241 smsusb_unregister();
1246 module_init(smscore_module_init);
1247 module_exit(smscore_module_exit);
1249 MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
1250 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1251 MODULE_LICENSE("GPL");