5 \brief Siano core API module
6 This file contains implementation for the interface to sms core component
8 \par Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
10 \par 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
15 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
18 \author Anatoly Greenblat
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/moduleparam.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/delay.h>
30 #include "smskdefs.h" // device, page, scatterlist, kmutex
32 #include <linux/firmware.h>
34 #include "smscoreapi.h"
39 typedef struct _smscore_device_notifyee
41 struct list_head entry
;
43 } smscore_device_notifyee_t
;
45 typedef struct _smscore_client
47 struct list_head entry
;
48 smscore_device_t
*coredev
;
54 onresponse_t onresponse_handler
;
55 onremove_t onremove_handler
;
58 typedef struct _smscore_subclient
60 struct list_head entry
;
61 smscore_client_t
*client
;
64 } smscore_subclient_t
;
66 typedef struct _smscore_device
68 struct list_head entry
;
70 struct list_head clients
;
71 struct list_head subclients
;
72 spinlock_t clientslock
;
74 struct list_head buffers
;
75 spinlock_t bufferslock
;
79 int common_buffer_size
;
80 dma_addr_t common_buffer_phys
;
83 struct device
*device
;
86 unsigned long device_flags
;
88 setmode_t setmode_handler
;
89 detectmode_t detectmode_handler
;
90 sendrequest_t sendrequest_handler
;
91 preload_t preload_handler
;
92 postload_t postload_handler
;
94 int mode
, modes_supported
;
96 struct completion version_ex_done
, data_download_done
, trigger_done
;
97 struct completion init_device_done
, reload_start_done
, resume_done
;
100 typedef struct _smscore_registry_entry
102 struct list_head entry
;
105 } smscore_registry_entry_t
;
107 struct list_head g_smscore_notifyees
;
108 struct list_head g_smscore_devices
;
109 kmutex_t g_smscore_deviceslock
;
111 struct list_head g_smscore_registry
;
112 kmutex_t g_smscore_registrylock
;
114 static int default_mode
= 1;
115 module_param(default_mode
, int, 0644);
116 MODULE_PARM_DESC(default_mode
, "default firmware id (device mode)");
118 int smscore_registry_getmode(char* devpath
)
120 smscore_registry_entry_t
*entry
;
121 struct list_head
*next
;
123 kmutex_lock(&g_smscore_registrylock
);
125 for (next
= g_smscore_registry
.next
; next
!= &g_smscore_registry
; next
= next
->next
)
127 entry
= (smscore_registry_entry_t
*) next
;
129 if (!strcmp(entry
->devpath
, devpath
))
131 kmutex_unlock(&g_smscore_registrylock
);
136 entry
= (smscore_registry_entry_t
*) kmalloc(sizeof(smscore_registry_entry_t
), GFP_KERNEL
);
139 entry
->mode
= default_mode
;
140 strcpy(entry
->devpath
, devpath
);
142 list_add(&entry
->entry
, &g_smscore_registry
);
145 kmutex_unlock(&g_smscore_registrylock
);
150 void smscore_registry_setmode(char* devpath
, int mode
)
152 smscore_registry_entry_t
*entry
;
153 struct list_head
*next
;
155 kmutex_lock(&g_smscore_registrylock
);
157 for (next
= g_smscore_registry
.next
; next
!= &g_smscore_registry
; next
= next
->next
)
159 entry
= (smscore_registry_entry_t
*) next
;
161 if (!strcmp(entry
->devpath
, devpath
))
168 kmutex_unlock(&g_smscore_registrylock
);
172 void list_add_locked(struct list_head
*new, struct list_head
*head
, spinlock_t
* lock
)
176 spin_lock_irqsave(lock
, flags
);
180 spin_unlock_irqrestore(lock
, flags
);
184 * register a client callback that called when device plugged in/unplugged
185 * NOTE: if devices exist callback is called immediately for each device
187 * @param hotplug callback
189 * @return 0 on success, <0 on error.
191 int smscore_register_hotplug(hotplug_t hotplug
)
193 smscore_device_notifyee_t
*notifyee
;
194 struct list_head
*next
, *first
;
197 kmutex_lock(&g_smscore_deviceslock
);
199 notifyee
= kmalloc(sizeof(smscore_device_notifyee_t
), GFP_KERNEL
);
202 // now notify callback about existing devices
203 first
= &g_smscore_devices
;
204 for (next
= first
->next
; next
!= first
&& !rc
; next
= next
->next
)
206 smscore_device_t
*coredev
= (smscore_device_t
*) next
;
207 rc
= hotplug(coredev
, coredev
->device
, 1);
212 notifyee
->hotplug
= hotplug
;
213 list_add(¬ifyee
->entry
, &g_smscore_notifyees
);
221 kmutex_unlock(&g_smscore_deviceslock
);
227 * unregister a client callback that called when device plugged in/unplugged
229 * @param hotplug callback
232 void smscore_unregister_hotplug(hotplug_t hotplug
)
234 struct list_head
*next
, *first
;
236 kmutex_lock(&g_smscore_deviceslock
);
238 first
= &g_smscore_notifyees
;
240 for (next
= first
->next
; next
!= first
;)
242 smscore_device_notifyee_t
*notifyee
= (smscore_device_notifyee_t
*) next
;
245 if (notifyee
->hotplug
== hotplug
)
247 list_del(¬ifyee
->entry
);
252 kmutex_unlock(&g_smscore_deviceslock
);
255 void smscore_notify_clients(smscore_device_t
*coredev
)
257 smscore_client_t
* client
;
259 // the client must call smscore_unregister_client from remove handler
260 while (!list_empty(&coredev
->clients
))
262 client
= (smscore_client_t
*) coredev
->clients
.next
;
263 client
->onremove_handler(client
->context
);
267 int smscore_notify_callbacks(smscore_device_t
*coredev
, struct device
*device
, int arrival
)
269 struct list_head
*next
, *first
;
272 // note: must be called under g_deviceslock
274 first
= &g_smscore_notifyees
;
276 for (next
= first
->next
; next
!= first
; next
= next
->next
)
278 rc
= ((smscore_device_notifyee_t
*) next
)->hotplug(coredev
, device
, arrival
);
286 smscore_buffer_t
*smscore_createbuffer(u8
* buffer
, void* common_buffer
, dma_addr_t common_buffer_phys
)
288 smscore_buffer_t
*cb
= kmalloc(sizeof(smscore_buffer_t
), GFP_KERNEL
);
291 printk(KERN_INFO
"%s kmalloc(...) failed\n", __FUNCTION__
);
296 cb
->offset_in_common
= buffer
- (u8
*) common_buffer
;
297 cb
->phys
= common_buffer_phys
+ cb
->offset_in_common
;
303 * creates coredev object for a device, prepares buffers, creates buffer mappings, notifies
304 * registered hotplugs about new device.
306 * @param params device pointer to struct with device specific parameters and handlers
307 * @param coredev pointer to a value that receives created coredev object
309 * @return 0 on success, <0 on error.
311 int smscore_register_device(smsdevice_params_t
*params
, smscore_device_t
**coredev
)
313 smscore_device_t
* dev
;
316 dev
= kzalloc(sizeof(smscore_device_t
), GFP_KERNEL
);
319 printk(KERN_INFO
"%s kzalloc(...) failed\n", __FUNCTION__
);
323 // init list entry so it could be safe in smscore_unregister_device
324 INIT_LIST_HEAD(&dev
->entry
);
327 INIT_LIST_HEAD(&dev
->clients
);
328 INIT_LIST_HEAD(&dev
->subclients
);
329 INIT_LIST_HEAD(&dev
->buffers
);
332 spin_lock_init(&dev
->clientslock
);
333 spin_lock_init(&dev
->bufferslock
);
335 // init completion events
336 init_completion(&dev
->version_ex_done
);
337 init_completion(&dev
->data_download_done
);
338 init_completion(&dev
->trigger_done
);
339 init_completion(&dev
->init_device_done
);
340 init_completion(&dev
->reload_start_done
);
341 init_completion(&dev
->resume_done
);
343 // alloc common buffer
344 dev
->common_buffer_size
= params
->buffer_size
* params
->num_buffers
;
345 dev
->common_buffer
= dma_alloc_coherent(NULL
, dev
->common_buffer_size
, &dev
->common_buffer_phys
, GFP_KERNEL
| GFP_DMA
);
346 if (!dev
->common_buffer
)
348 smscore_unregister_device(dev
);
352 // prepare dma buffers
353 for (buffer
= dev
->common_buffer
; dev
->num_buffers
< params
->num_buffers
; dev
->num_buffers
++, buffer
+= params
->buffer_size
)
355 smscore_buffer_t
*cb
= smscore_createbuffer(buffer
, dev
->common_buffer
, dev
->common_buffer_phys
);
358 smscore_unregister_device(dev
);
362 smscore_putbuffer(dev
, cb
);
365 printk(KERN_INFO
"%s allocated %d buffers\n", __FUNCTION__
, dev
->num_buffers
);
367 dev
->mode
= DEVICE_MODE_NONE
;
368 dev
->context
= params
->context
;
369 dev
->device
= params
->device
;
370 dev
->setmode_handler
= params
->setmode_handler
;
371 dev
->detectmode_handler
= params
->detectmode_handler
;
372 dev
->sendrequest_handler
= params
->sendrequest_handler
;
373 dev
->preload_handler
= params
->preload_handler
;
374 dev
->postload_handler
= params
->postload_handler
;
376 dev
->device_flags
= params
->flags
;
377 strcpy(dev
->devpath
, params
->devpath
);
379 // add device to devices list
380 kmutex_lock(&g_smscore_deviceslock
);
381 list_add(&dev
->entry
, &g_smscore_devices
);
382 kmutex_unlock(&g_smscore_deviceslock
);
386 printk(KERN_INFO
"%s device %p created\n", __FUNCTION__
, dev
);
392 * sets initial device mode and notifies client hotplugs that device is ready
394 * @param coredev pointer to a coredev object returned by smscore_register_device
396 * @return 0 on success, <0 on error.
398 int smscore_start_device(smscore_device_t
*coredev
)
400 int rc
= smscore_set_device_mode(coredev
, smscore_registry_getmode(coredev
->devpath
));
404 kmutex_lock(&g_smscore_deviceslock
);
406 rc
= smscore_notify_callbacks(coredev
, coredev
->device
, 1);
408 printk(KERN_INFO
"%s device %p started, rc %d\n", __FUNCTION__
, coredev
, rc
);
410 kmutex_unlock(&g_smscore_deviceslock
);
415 int smscore_sendrequest_and_wait(smscore_device_t
*coredev
, void* buffer
, size_t size
, struct completion
*completion
)
417 int rc
= coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
421 return wait_for_completion_timeout(completion
, msecs_to_jiffies(1000)) ? 0 : -ETIME
;
424 int smscore_load_firmware_family2(smscore_device_t
*coredev
, void *buffer
, size_t size
)
426 SmsFirmware_ST
* firmware
= (SmsFirmware_ST
*) buffer
;
428 UINT32 mem_address
= firmware
->StartAddress
;
429 u8
* payload
= firmware
->Payload
;
432 if (coredev
->preload_handler
)
434 rc
= coredev
->preload_handler(coredev
->context
);
439 // PAGE_SIZE buffer shall be enough and dma aligned
440 msg
= (SmsMsgHdr_ST
*) kmalloc(PAGE_SIZE
, GFP_KERNEL
| GFP_DMA
);
444 if (coredev
->mode
!= DEVICE_MODE_NONE
)
446 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_START_REQ
, sizeof(SmsMsgHdr_ST
));
447 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->reload_start_done
);
448 mem_address
= *(UINT32
*) &payload
[20];
451 while (size
&& rc
>= 0)
453 SmsDataDownload_ST
*DataMsg
= (SmsDataDownload_ST
*) msg
;
454 int payload_size
= min((int) size
, SMS_MAX_PAYLOAD_SIZE
);
456 SMS_INIT_MSG(msg
, MSG_SMS_DATA_DOWNLOAD_REQ
, (UINT16
)(sizeof(SmsMsgHdr_ST
) + sizeof(UINT32
) + payload_size
));
458 DataMsg
->MemAddr
= mem_address
;
459 memcpy(DataMsg
->Payload
, payload
, payload_size
);
461 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
&& coredev
->mode
== DEVICE_MODE_NONE
)
462 rc
= coredev
->sendrequest_handler(coredev
->context
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
);
464 rc
= smscore_sendrequest_and_wait(coredev
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
, &coredev
->data_download_done
);
466 payload
+= payload_size
;
467 size
-= payload_size
;
468 mem_address
+= payload_size
;
473 if (coredev
->mode
== DEVICE_MODE_NONE
)
475 SmsMsgData_ST
* TriggerMsg
= (SmsMsgData_ST
*) msg
;
477 SMS_INIT_MSG(msg
, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ
, sizeof(SmsMsgHdr_ST
) + sizeof(UINT32
) * 5);
479 TriggerMsg
->msgData
[0] = firmware
->StartAddress
; // Entry point
480 TriggerMsg
->msgData
[1] = 5; // Priority
481 TriggerMsg
->msgData
[2] = 0x200; // Stack size
482 TriggerMsg
->msgData
[3] = 0; // Parameter
483 TriggerMsg
->msgData
[4] = 4; // Task ID
485 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
)
487 rc
= coredev
->sendrequest_handler(coredev
->context
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
);
491 rc
= smscore_sendrequest_and_wait(coredev
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
, &coredev
->trigger_done
);
495 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_EXEC_REQ
, sizeof(SmsMsgHdr_ST
));
497 rc
= coredev
->sendrequest_handler(coredev
->context
, msg
, msg
->msgLength
);
501 printk("%s %d \n", __func__
, rc
);
505 return (rc
>= 0 && coredev
->postload_handler
) ?
506 coredev
->postload_handler(coredev
->context
) :
511 * loads specified firmware into a buffer and calls device loadfirmware_handler
513 * @param coredev pointer to a coredev object returned by smscore_register_device
514 * @param filename null-terminated string specifies firmware file name
515 * @param loadfirmware_handler device handler that loads firmware
517 * @return 0 on success, <0 on error.
519 int smscore_load_firmware(smscore_device_t
*coredev
, char* filename
, loadfirmware_t loadfirmware_handler
)
523 const struct firmware
*fw
;
526 if (loadfirmware_handler
== NULL
&& !(coredev
->device_flags
& SMS_DEVICE_FAMILY2
))
529 rc
= request_firmware(&fw
, filename
, coredev
->device
);
532 printk(KERN_INFO
"%s failed to open \"%s\"\n", __FUNCTION__
, filename
);
536 fw_buffer
= kmalloc(ALIGN(fw
->size
, SMS_ALLOC_ALIGNMENT
), GFP_KERNEL
| GFP_DMA
);
539 memcpy(fw_buffer
, fw
->data
, fw
->size
);
541 rc
= (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) ?
542 smscore_load_firmware_family2(coredev
, fw_buffer
, fw
->size
) :
543 loadfirmware_handler(coredev
->context
, fw_buffer
, fw
->size
);
549 printk(KERN_INFO
"%s failed to allocate firmware buffer\n", __FUNCTION__
);
553 release_firmware(fw
);
559 * notifies all clients registered with the device, notifies hotplugs, frees all buffers and coredev object
561 * @param coredev pointer to a coredev object returned by smscore_register_device
563 * @return 0 on success, <0 on error.
565 void smscore_unregister_device(smscore_device_t
*coredev
)
567 smscore_buffer_t
*cb
;
570 kmutex_lock(&g_smscore_deviceslock
);
572 smscore_notify_clients(coredev
);
573 smscore_notify_callbacks(coredev
, NULL
, 0);
575 // at this point all buffers should be back
576 // onresponse must no longer be called
580 while ((cb
= smscore_getbuffer(coredev
)))
586 if (num_buffers
== coredev
->num_buffers
)
589 printk(KERN_INFO
"%s waiting for %d buffer(s)\n", __FUNCTION__
, coredev
->num_buffers
- num_buffers
);
593 printk(KERN_INFO
"%s freed %d buffers\n", __FUNCTION__
, num_buffers
);
595 if (coredev
->common_buffer
)
596 dma_free_coherent(NULL
, coredev
->common_buffer_size
, coredev
->common_buffer
, coredev
->common_buffer_phys
);
598 list_del(&coredev
->entry
);
601 kmutex_unlock(&g_smscore_deviceslock
);
603 printk(KERN_INFO
"%s device %p destroyed\n", __FUNCTION__
, coredev
);
606 int smscore_detect_mode(smscore_device_t
*coredev
)
608 void *buffer
= kmalloc(sizeof(SmsMsgHdr_ST
) + SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
609 SmsMsgHdr_ST
*msg
= (SmsMsgHdr_ST
*) SMS_ALIGN_ADDRESS(buffer
);
615 SMS_INIT_MSG(msg
, MSG_SMS_GET_VERSION_EX_REQ
, sizeof(SmsMsgHdr_ST
));
617 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->version_ex_done
);
620 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed first try\n", __FUNCTION__
);
622 if (wait_for_completion_timeout(&coredev
->resume_done
, msecs_to_jiffies(5000)))
624 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->version_ex_done
);
627 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n", __FUNCTION__
, rc
);
639 char *smscore_fw_lkup
[] =
641 "dvb_nova_12mhz.inp",
642 "dvb_nova_12mhz.inp",
645 "dvb_nova_12mhz.inp",
646 "isdbt_nova_12mhz.inp",
647 "isdbt_nova_12mhz.inp",
648 "cmmb_nova_12mhz.inp",
653 * calls device handler to change mode of operation
654 * NOTE: stellar/usb may disconnect when changing mode
656 * @param coredev pointer to a coredev object returned by smscore_register_device
657 * @param mode requested mode of operation
659 * @return 0 on success, <0 on error.
661 int smscore_set_device_mode(smscore_device_t
*coredev
, int mode
)
666 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
)
668 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_RAW_TUNER
)
670 printk(KERN_INFO
"%s invalid mode specified %d\n", __FUNCTION__
, mode
);
674 if (!(coredev
->device_flags
& SMS_DEVICE_NOT_READY
))
676 rc
= smscore_detect_mode(coredev
);
681 if (coredev
->mode
== mode
)
683 printk(KERN_INFO
"%s device mode %d already set\n", __FUNCTION__
, mode
);
687 if (!(coredev
->modes_supported
& (1 << mode
)))
689 rc
= smscore_load_firmware(coredev
, smscore_fw_lkup
[mode
], NULL
);
695 printk(KERN_INFO
"%s mode %d supported by running firmware\n", __FUNCTION__
, mode
);
698 buffer
= kmalloc(sizeof(SmsMsgData_ST
) + SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
701 SmsMsgData_ST
*msg
= (SmsMsgData_ST
*) SMS_ALIGN_ADDRESS(buffer
);
703 SMS_INIT_MSG(&msg
->xMsgHeader
, MSG_SMS_INIT_DEVICE_REQ
, sizeof(SmsMsgData_ST
));
704 msg
->msgData
[0] = mode
;
706 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->xMsgHeader
.msgLength
, &coredev
->init_device_done
);
715 if (coredev
->detectmode_handler
)
716 coredev
->detectmode_handler(coredev
->context
, &coredev
->mode
);
718 if (coredev
->mode
!= mode
&& coredev
->setmode_handler
)
719 rc
= coredev
->setmode_handler(coredev
->context
, mode
);
722 smscore_registry_setmode(coredev
->devpath
, mode
);
726 coredev
->mode
= mode
;
727 coredev
->device_flags
&= ~SMS_DEVICE_NOT_READY
;
734 * calls device handler to get current mode of operation
736 * @param coredev pointer to a coredev object returned by smscore_register_device
738 * @return current mode
740 int smscore_get_device_mode(smscore_device_t
*coredev
)
742 return coredev
->mode
;
745 smscore_client_t
* smscore_getclient_by_type(smscore_device_t
*coredev
, int data_type
)
747 smscore_client_t
*client
= NULL
;
748 struct list_head
*next
, *first
;
754 spin_lock_irqsave(&coredev
->clientslock
, flags
);
756 first
= &coredev
->clients
;
758 for (next
= first
->next
; next
!= first
; next
= next
->next
)
760 if (((smscore_client_t
*) next
)->data_type
== data_type
)
762 client
= (smscore_client_t
*) next
;
767 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
772 smscore_client_t
* smscore_getclient_by_id(smscore_device_t
*coredev
, int id
)
774 smscore_client_t
*client
= NULL
;
775 struct list_head
*next
, *first
;
778 spin_lock_irqsave(&coredev
->clientslock
, flags
);
780 first
= &coredev
->subclients
;
782 for (next
= first
->next
; next
!= first
; next
= next
->next
)
784 if (((smscore_subclient_t
*) next
)->id
== id
)
786 client
= ((smscore_subclient_t
*) next
)->client
;
791 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
797 * find client by response id/type, call clients onresponse handler
798 * return buffer to pool on error
800 * @param coredev pointer to a coredev object returned by smscore_register_device
801 * @param cb pointer to response buffer descriptor
804 void smscore_onresponse(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
806 SmsMsgHdr_ST
*phdr
= (SmsMsgHdr_ST
*)((u8
*) cb
->p
+ cb
->offset
);
807 smscore_client_t
* client
= smscore_getclient_by_type(coredev
, phdr
->msgType
);
810 static unsigned long last_sample_time
= 0;
811 static int data_total
= 0;
812 unsigned long time_now
= jiffies_to_msecs(jiffies
);
814 if (!last_sample_time
)
815 last_sample_time
= time_now
;
817 if (time_now
- last_sample_time
> 10000)
819 printk("\n%s data rate %d bytes/secs\n", __func__
, (int)((data_total
* 1000) / (time_now
- last_sample_time
)));
821 last_sample_time
= time_now
;
825 data_total
+= cb
->size
;
828 client
= smscore_getclient_by_id(coredev
, phdr
->msgDstId
);
831 rc
= client
->onresponse_handler(client
->context
, cb
);
835 switch (phdr
->msgType
)
837 case MSG_SMS_GET_VERSION_EX_RES
:
839 SmsVersionRes_ST
*ver
= (SmsVersionRes_ST
*) phdr
;
840 printk("%s: MSG_SMS_GET_VERSION_EX_RES id %d prots 0x%x ver %d.%d\n", __FUNCTION__
, ver
->FirmwareId
, ver
->SupportedProtocols
, ver
->RomVersionMajor
, ver
->RomVersionMinor
);
842 coredev
->mode
= ver
->FirmwareId
== 255 ? DEVICE_MODE_NONE
: ver
->FirmwareId
;
843 coredev
->modes_supported
= ver
->SupportedProtocols
;
845 complete(&coredev
->version_ex_done
);
849 case MSG_SMS_INIT_DEVICE_RES
:
850 printk("%s: MSG_SMS_INIT_DEVICE_RES\n", __FUNCTION__
);
851 complete(&coredev
->init_device_done
);
854 case MSG_SW_RELOAD_START_RES
:
855 printk("%s: MSG_SW_RELOAD_START_RES\n", __FUNCTION__
);
856 complete(&coredev
->reload_start_done
);
859 case MSG_SMS_DATA_DOWNLOAD_RES
:
860 complete(&coredev
->data_download_done
);
863 case MSG_SW_RELOAD_EXEC_RES
:
864 printk("%s: MSG_SW_RELOAD_EXEC_RES\n", __FUNCTION__
);
867 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES
:
868 printk("%s: MSG_SMS_SWDOWNLOAD_TRIGGER_RES\n", __FUNCTION__
);
869 complete(&coredev
->trigger_done
);
872 case MSG_SMS_SLEEP_RESUME_COMP_IND
:
873 complete(&coredev
->resume_done
);
877 printk(KERN_INFO
"%s no client (%p) or error (%d), type:%d dstid:%d\n", __FUNCTION__
, client
, rc
, phdr
->msgType
, phdr
->msgDstId
);
880 smscore_putbuffer(coredev
, cb
);
885 * return pointer to next free buffer descriptor from core pool
887 * @param coredev pointer to a coredev object returned by smscore_register_device
889 * @return pointer to descriptor on success, NULL on error.
891 smscore_buffer_t
*smscore_getbuffer(smscore_device_t
*coredev
)
893 smscore_buffer_t
*cb
= NULL
;
896 spin_lock_irqsave(&coredev
->bufferslock
, flags
);
898 if (!list_empty(&coredev
->buffers
))
900 cb
= (smscore_buffer_t
*) coredev
->buffers
.next
;
901 list_del(&cb
->entry
);
904 spin_unlock_irqrestore(&coredev
->bufferslock
, flags
);
910 * return buffer descriptor to a pool
912 * @param coredev pointer to a coredev object returned by smscore_register_device
913 * @param cb pointer buffer descriptor
916 void smscore_putbuffer(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
918 list_add_locked(&cb
->entry
, &coredev
->buffers
, &coredev
->bufferslock
);
921 int smscore_validate_client(smscore_device_t
*coredev
, smscore_client_t
*client
, int id
)
923 smscore_client_t
*existing_client
;
924 smscore_subclient_t
*subclient
;
929 existing_client
= smscore_getclient_by_id(coredev
, id
);
930 if (existing_client
== client
)
936 subclient
= kzalloc(sizeof(smscore_subclient_t
), GFP_KERNEL
);
940 subclient
->client
= client
;
943 list_add_locked(&subclient
->entry
, &coredev
->subclients
, &coredev
->clientslock
);
949 * creates smsclient object, check that id is taken by another client
951 * @param coredev pointer to a coredev object from clients hotplug
952 * @param initial_id all messages with this id would be sent to this client
953 * @param data_type all messages of this type would be sent to this client
954 * @param onresponse_handler client handler that is called to process incoming messages
955 * @param onremove_handler client handler that is called when device is removed
956 * @param context client-specific context
957 * @param client pointer to a value that receives created smsclient object
959 * @return 0 on success, <0 on error.
961 int smscore_register_client(smscore_device_t
*coredev
, smsclient_params_t
*params
, smscore_client_t
**client
)
963 smscore_client_t
* newclient
;
966 // check that no other channel with same data type exists
967 if (params
->data_type
&& smscore_getclient_by_type(coredev
, params
->data_type
))
970 newclient
= kzalloc(sizeof(smscore_client_t
), GFP_KERNEL
);
974 // check that no other channel with same id exists
975 rc
= smscore_validate_client(coredev
, newclient
, params
->initial_id
);
982 newclient
->coredev
= coredev
;
983 newclient
->data_type
= params
->data_type
;
984 newclient
->onresponse_handler
= params
->onresponse_handler
;
985 newclient
->onremove_handler
= params
->onremove_handler
;
986 newclient
->context
= params
->context
;
988 list_add_locked(&newclient
->entry
, &coredev
->clients
, &coredev
->clientslock
);
992 printk(KERN_INFO
"%s %p %d %d\n", __FUNCTION__
, params
->context
, params
->data_type
, params
->initial_id
);
998 * frees smsclient object and all subclients associated with it
1000 * @param client pointer to smsclient object returned by smscore_register_client
1003 void smscore_unregister_client(smscore_client_t
*client
)
1005 smscore_device_t
*coredev
= client
->coredev
;
1006 struct list_head
*next
, *first
;
1007 unsigned long flags
;
1009 spin_lock_irqsave(&coredev
->clientslock
, flags
);
1011 first
= &coredev
->subclients
;
1013 for (next
= first
->next
; next
!= first
;)
1015 smscore_subclient_t
*subclient
= (smscore_subclient_t
*) next
;
1018 if (subclient
->client
== client
)
1020 list_del(&subclient
->entry
);
1025 printk(KERN_INFO
"%s %p %d\n", __FUNCTION__
, client
->context
, client
->data_type
);
1027 list_del(&client
->entry
);
1030 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
1034 * verifies that source id is not taken by another client,
1035 * calls device handler to send requests to the device
1037 * @param client pointer to smsclient object returned by smscore_register_client
1038 * @param buffer pointer to a request buffer
1039 * @param size size (in bytes) of request buffer
1041 * @return 0 on success, <0 on error.
1043 int smsclient_sendrequest(smscore_client_t
*client
, void *buffer
, size_t size
)
1045 smscore_device_t
* coredev
= client
->coredev
;
1046 SmsMsgHdr_ST
* phdr
= (SmsMsgHdr_ST
*) buffer
;
1048 // check that no other channel with same id exists
1049 int rc
= smscore_validate_client(client
->coredev
, client
, phdr
->msgSrcId
);
1053 return coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
1057 * return the size of large (common) buffer
1059 * @param coredev pointer to a coredev object from clients hotplug
1061 * @return size (in bytes) of the buffer
1063 int smscore_get_common_buffer_size(smscore_device_t
*coredev
)
1065 return coredev
->common_buffer_size
;
1069 * maps common buffer (if supported by platform)
1071 * @param coredev pointer to a coredev object from clients hotplug
1072 * @param vma pointer to vma struct from mmap handler
1074 * @return 0 on success, <0 on error.
1076 int smscore_map_common_buffer(smscore_device_t
*coredev
, struct vm_area_struct
* vma
)
1078 unsigned long end
= vma
->vm_end
, start
= vma
->vm_start
, size
= PAGE_ALIGN(coredev
->common_buffer_size
);
1080 if (!(vma
->vm_flags
& (VM_READ
| VM_SHARED
)) || (vma
->vm_flags
& VM_WRITE
))
1082 printk(KERN_INFO
"%s invalid vm flags\n", __FUNCTION__
);
1086 if ((end
- start
) != size
)
1088 printk(KERN_INFO
"%s invalid size %d expected %d\n", __FUNCTION__
, (int)(end
- start
), (int) size
);
1092 if (remap_pfn_range(vma
, start
, coredev
->common_buffer_phys
>> PAGE_SHIFT
, size
, pgprot_noncached(vma
->vm_page_prot
)))
1094 printk(KERN_INFO
"%s remap_page_range failed\n", __FUNCTION__
);
1101 int smscore_module_init(void)
1105 INIT_LIST_HEAD(&g_smscore_notifyees
);
1106 INIT_LIST_HEAD(&g_smscore_devices
);
1107 kmutex_init(&g_smscore_deviceslock
);
1109 INIT_LIST_HEAD(&g_smscore_registry
);
1110 kmutex_init(&g_smscore_registrylock
);
1112 rc
= smschar_initialize();
1114 printk(KERN_INFO
"%s, rc %d\n", __FUNCTION__
, rc
);
1119 void smscore_module_exit(void)
1121 smschar_terminate();
1123 kmutex_lock(&g_smscore_deviceslock
);
1124 while (!list_empty(&g_smscore_notifyees
))
1126 smscore_device_notifyee_t
*notifyee
= (smscore_device_notifyee_t
*) g_smscore_notifyees
.next
;
1128 list_del(¬ifyee
->entry
);
1131 kmutex_unlock(&g_smscore_deviceslock
);
1133 kmutex_lock(&g_smscore_registrylock
);
1134 while (!list_empty(&g_smscore_registry
))
1136 smscore_registry_entry_t
*entry
= (smscore_registry_entry_t
*) g_smscore_registry
.next
;
1138 list_del(&entry
->entry
);
1141 kmutex_unlock(&g_smscore_registrylock
);
1143 printk(KERN_INFO
"%s\n", __FUNCTION__
);
1146 module_init(smscore_module_init
);
1147 module_exit(smscore_module_exit
);
1149 MODULE_DESCRIPTION("smscore");
1150 MODULE_AUTHOR("Anatoly Greenblatt,,, (anatolyg@siano-ms.com)");
1151 MODULE_LICENSE("GPL");
1153 EXPORT_SYMBOL(smscore_registry_setmode
);
1154 EXPORT_SYMBOL(smscore_registry_getmode
);
1155 EXPORT_SYMBOL(smscore_register_hotplug
);
1156 EXPORT_SYMBOL(smscore_unregister_hotplug
);
1157 EXPORT_SYMBOL(smscore_register_device
);
1158 EXPORT_SYMBOL(smscore_unregister_device
);
1159 EXPORT_SYMBOL(smscore_start_device
);
1160 EXPORT_SYMBOL(smscore_load_firmware
);
1161 EXPORT_SYMBOL(smscore_set_device_mode
);
1162 EXPORT_SYMBOL(smscore_get_device_mode
);
1163 EXPORT_SYMBOL(smscore_register_client
);
1164 EXPORT_SYMBOL(smscore_unregister_client
);
1165 EXPORT_SYMBOL(smsclient_sendrequest
);
1166 EXPORT_SYMBOL(smscore_onresponse
);
1167 EXPORT_SYMBOL(smscore_get_common_buffer_size
);
1168 EXPORT_SYMBOL(smscore_map_common_buffer
);
1169 EXPORT_SYMBOL(smscore_getbuffer
);
1170 EXPORT_SYMBOL(smscore_putbuffer
);