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 <linux/firmware.h>
32 #include "smscoreapi.h"
34 typedef struct _smscore_device_notifyee
36 struct list_head entry
;
38 } smscore_device_notifyee_t
;
40 typedef struct _smscore_client
42 struct list_head entry
;
43 smscore_device_t
*coredev
;
49 onresponse_t onresponse_handler
;
50 onremove_t onremove_handler
;
53 typedef struct _smscore_subclient
55 struct list_head entry
;
56 smscore_client_t
*client
;
59 } smscore_subclient_t
;
61 typedef struct _smscore_device
63 struct list_head entry
;
65 struct list_head clients
;
66 struct list_head subclients
;
67 spinlock_t clientslock
;
69 struct list_head buffers
;
70 spinlock_t bufferslock
;
74 int common_buffer_size
;
75 dma_addr_t common_buffer_phys
;
78 struct device
*device
;
81 unsigned long device_flags
;
83 setmode_t setmode_handler
;
84 detectmode_t detectmode_handler
;
85 sendrequest_t sendrequest_handler
;
86 preload_t preload_handler
;
87 postload_t postload_handler
;
89 int mode
, modes_supported
;
91 struct completion version_ex_done
, data_download_done
, trigger_done
;
92 struct completion init_device_done
, reload_start_done
, resume_done
;
95 typedef struct _smscore_registry_entry
97 struct list_head entry
;
100 } smscore_registry_entry_t
;
102 struct list_head g_smscore_notifyees
;
103 struct list_head g_smscore_devices
;
104 kmutex_t g_smscore_deviceslock
;
106 struct list_head g_smscore_registry
;
107 kmutex_t g_smscore_registrylock
;
109 static int default_mode
= 1;
110 module_param(default_mode
, int, 0644);
111 MODULE_PARM_DESC(default_mode
, "default firmware id (device mode)");
113 int smscore_registry_getmode(char* devpath
)
115 smscore_registry_entry_t
*entry
;
116 struct list_head
*next
;
118 kmutex_lock(&g_smscore_registrylock
);
120 for (next
= g_smscore_registry
.next
; next
!= &g_smscore_registry
; next
= next
->next
)
122 entry
= (smscore_registry_entry_t
*) next
;
124 if (!strcmp(entry
->devpath
, devpath
))
126 kmutex_unlock(&g_smscore_registrylock
);
131 entry
= (smscore_registry_entry_t
*) kmalloc(sizeof(smscore_registry_entry_t
), GFP_KERNEL
);
134 entry
->mode
= default_mode
;
135 strcpy(entry
->devpath
, devpath
);
137 list_add(&entry
->entry
, &g_smscore_registry
);
140 kmutex_unlock(&g_smscore_registrylock
);
145 void smscore_registry_setmode(char* devpath
, int mode
)
147 smscore_registry_entry_t
*entry
;
148 struct list_head
*next
;
150 kmutex_lock(&g_smscore_registrylock
);
152 for (next
= g_smscore_registry
.next
; next
!= &g_smscore_registry
; next
= next
->next
)
154 entry
= (smscore_registry_entry_t
*) next
;
156 if (!strcmp(entry
->devpath
, devpath
))
163 kmutex_unlock(&g_smscore_registrylock
);
167 void list_add_locked(struct list_head
*new, struct list_head
*head
, spinlock_t
* lock
)
171 spin_lock_irqsave(lock
, flags
);
175 spin_unlock_irqrestore(lock
, flags
);
179 * register a client callback that called when device plugged in/unplugged
180 * NOTE: if devices exist callback is called immediately for each device
182 * @param hotplug callback
184 * @return 0 on success, <0 on error.
186 int smscore_register_hotplug(hotplug_t hotplug
)
188 smscore_device_notifyee_t
*notifyee
;
189 struct list_head
*next
, *first
;
192 kmutex_lock(&g_smscore_deviceslock
);
194 notifyee
= kmalloc(sizeof(smscore_device_notifyee_t
), GFP_KERNEL
);
197 // now notify callback about existing devices
198 first
= &g_smscore_devices
;
199 for (next
= first
->next
; next
!= first
&& !rc
; next
= next
->next
)
201 smscore_device_t
*coredev
= (smscore_device_t
*) next
;
202 rc
= hotplug(coredev
, coredev
->device
, 1);
207 notifyee
->hotplug
= hotplug
;
208 list_add(¬ifyee
->entry
, &g_smscore_notifyees
);
216 kmutex_unlock(&g_smscore_deviceslock
);
222 * unregister a client callback that called when device plugged in/unplugged
224 * @param hotplug callback
227 void smscore_unregister_hotplug(hotplug_t hotplug
)
229 struct list_head
*next
, *first
;
231 kmutex_lock(&g_smscore_deviceslock
);
233 first
= &g_smscore_notifyees
;
235 for (next
= first
->next
; next
!= first
;)
237 smscore_device_notifyee_t
*notifyee
= (smscore_device_notifyee_t
*) next
;
240 if (notifyee
->hotplug
== hotplug
)
242 list_del(¬ifyee
->entry
);
247 kmutex_unlock(&g_smscore_deviceslock
);
250 void smscore_notify_clients(smscore_device_t
*coredev
)
252 smscore_client_t
* client
;
254 // the client must call smscore_unregister_client from remove handler
255 while (!list_empty(&coredev
->clients
))
257 client
= (smscore_client_t
*) coredev
->clients
.next
;
258 client
->onremove_handler(client
->context
);
262 int smscore_notify_callbacks(smscore_device_t
*coredev
, struct device
*device
, int arrival
)
264 struct list_head
*next
, *first
;
267 // note: must be called under g_deviceslock
269 first
= &g_smscore_notifyees
;
271 for (next
= first
->next
; next
!= first
; next
= next
->next
)
273 rc
= ((smscore_device_notifyee_t
*) next
)->hotplug(coredev
, device
, arrival
);
281 smscore_buffer_t
*smscore_createbuffer(u8
* buffer
, void* common_buffer
, dma_addr_t common_buffer_phys
)
283 smscore_buffer_t
*cb
= kmalloc(sizeof(smscore_buffer_t
), GFP_KERNEL
);
286 printk(KERN_INFO
"%s kmalloc(...) failed\n", __FUNCTION__
);
291 cb
->offset_in_common
= buffer
- (u8
*) common_buffer
;
292 cb
->phys
= common_buffer_phys
+ cb
->offset_in_common
;
298 * creates coredev object for a device, prepares buffers, creates buffer mappings, notifies
299 * registered hotplugs about new device.
301 * @param params device pointer to struct with device specific parameters and handlers
302 * @param coredev pointer to a value that receives created coredev object
304 * @return 0 on success, <0 on error.
306 int smscore_register_device(smsdevice_params_t
*params
, smscore_device_t
**coredev
)
308 smscore_device_t
* dev
;
311 dev
= kzalloc(sizeof(smscore_device_t
), GFP_KERNEL
);
314 printk(KERN_INFO
"%s kzalloc(...) failed\n", __FUNCTION__
);
318 // init list entry so it could be safe in smscore_unregister_device
319 INIT_LIST_HEAD(&dev
->entry
);
322 INIT_LIST_HEAD(&dev
->clients
);
323 INIT_LIST_HEAD(&dev
->subclients
);
324 INIT_LIST_HEAD(&dev
->buffers
);
327 spin_lock_init(&dev
->clientslock
);
328 spin_lock_init(&dev
->bufferslock
);
330 // init completion events
331 init_completion(&dev
->version_ex_done
);
332 init_completion(&dev
->data_download_done
);
333 init_completion(&dev
->trigger_done
);
334 init_completion(&dev
->init_device_done
);
335 init_completion(&dev
->reload_start_done
);
336 init_completion(&dev
->resume_done
);
338 // alloc common buffer
339 dev
->common_buffer_size
= params
->buffer_size
* params
->num_buffers
;
340 dev
->common_buffer
= dma_alloc_coherent(NULL
, dev
->common_buffer_size
, &dev
->common_buffer_phys
, GFP_KERNEL
| GFP_DMA
);
341 if (!dev
->common_buffer
)
343 smscore_unregister_device(dev
);
347 // prepare dma buffers
348 for (buffer
= dev
->common_buffer
; dev
->num_buffers
< params
->num_buffers
; dev
->num_buffers
++, buffer
+= params
->buffer_size
)
350 smscore_buffer_t
*cb
= smscore_createbuffer(buffer
, dev
->common_buffer
, dev
->common_buffer_phys
);
353 smscore_unregister_device(dev
);
357 smscore_putbuffer(dev
, cb
);
360 printk(KERN_INFO
"%s allocated %d buffers\n", __FUNCTION__
, dev
->num_buffers
);
362 dev
->mode
= DEVICE_MODE_NONE
;
363 dev
->context
= params
->context
;
364 dev
->device
= params
->device
;
365 dev
->setmode_handler
= params
->setmode_handler
;
366 dev
->detectmode_handler
= params
->detectmode_handler
;
367 dev
->sendrequest_handler
= params
->sendrequest_handler
;
368 dev
->preload_handler
= params
->preload_handler
;
369 dev
->postload_handler
= params
->postload_handler
;
371 dev
->device_flags
= params
->flags
;
372 strcpy(dev
->devpath
, params
->devpath
);
374 // add device to devices list
375 kmutex_lock(&g_smscore_deviceslock
);
376 list_add(&dev
->entry
, &g_smscore_devices
);
377 kmutex_unlock(&g_smscore_deviceslock
);
381 printk(KERN_INFO
"%s device %p created\n", __FUNCTION__
, dev
);
387 * sets initial device mode and notifies client hotplugs that device is ready
389 * @param coredev pointer to a coredev object returned by smscore_register_device
391 * @return 0 on success, <0 on error.
393 int smscore_start_device(smscore_device_t
*coredev
)
395 int rc
= smscore_set_device_mode(coredev
, smscore_registry_getmode(coredev
->devpath
));
399 kmutex_lock(&g_smscore_deviceslock
);
401 rc
= smscore_notify_callbacks(coredev
, coredev
->device
, 1);
403 printk(KERN_INFO
"%s device %p started, rc %d\n", __FUNCTION__
, coredev
, rc
);
405 kmutex_unlock(&g_smscore_deviceslock
);
410 int smscore_sendrequest_and_wait(smscore_device_t
*coredev
, void* buffer
, size_t size
, struct completion
*completion
)
412 int rc
= coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
416 return wait_for_completion_timeout(completion
, msecs_to_jiffies(1000)) ? 0 : -ETIME
;
419 int smscore_load_firmware_family2(smscore_device_t
*coredev
, void *buffer
, size_t size
)
421 SmsFirmware_ST
* firmware
= (SmsFirmware_ST
*) buffer
;
423 UINT32 mem_address
= firmware
->StartAddress
;
424 u8
* payload
= firmware
->Payload
;
427 if (coredev
->preload_handler
)
429 rc
= coredev
->preload_handler(coredev
->context
);
434 // PAGE_SIZE buffer shall be enough and dma aligned
435 msg
= (SmsMsgHdr_ST
*) kmalloc(PAGE_SIZE
, GFP_KERNEL
| GFP_DMA
);
439 if (coredev
->mode
!= DEVICE_MODE_NONE
)
441 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_START_REQ
, sizeof(SmsMsgHdr_ST
));
442 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->reload_start_done
);
443 mem_address
= *(UINT32
*) &payload
[20];
446 while (size
&& rc
>= 0)
448 SmsDataDownload_ST
*DataMsg
= (SmsDataDownload_ST
*) msg
;
449 int payload_size
= min((int) size
, SMS_MAX_PAYLOAD_SIZE
);
451 SMS_INIT_MSG(msg
, MSG_SMS_DATA_DOWNLOAD_REQ
, (UINT16
)(sizeof(SmsMsgHdr_ST
) + sizeof(UINT32
) + payload_size
));
453 DataMsg
->MemAddr
= mem_address
;
454 memcpy(DataMsg
->Payload
, payload
, payload_size
);
456 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
&& coredev
->mode
== DEVICE_MODE_NONE
)
457 rc
= coredev
->sendrequest_handler(coredev
->context
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
);
459 rc
= smscore_sendrequest_and_wait(coredev
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
, &coredev
->data_download_done
);
461 payload
+= payload_size
;
462 size
-= payload_size
;
463 mem_address
+= payload_size
;
468 if (coredev
->mode
== DEVICE_MODE_NONE
)
470 SmsMsgData_ST
* TriggerMsg
= (SmsMsgData_ST
*) msg
;
472 SMS_INIT_MSG(msg
, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ
, sizeof(SmsMsgHdr_ST
) + sizeof(UINT32
) * 5);
474 TriggerMsg
->msgData
[0] = firmware
->StartAddress
; // Entry point
475 TriggerMsg
->msgData
[1] = 5; // Priority
476 TriggerMsg
->msgData
[2] = 0x200; // Stack size
477 TriggerMsg
->msgData
[3] = 0; // Parameter
478 TriggerMsg
->msgData
[4] = 4; // Task ID
480 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
)
482 rc
= coredev
->sendrequest_handler(coredev
->context
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
);
486 rc
= smscore_sendrequest_and_wait(coredev
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
, &coredev
->trigger_done
);
490 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_EXEC_REQ
, sizeof(SmsMsgHdr_ST
));
492 rc
= coredev
->sendrequest_handler(coredev
->context
, msg
, msg
->msgLength
);
496 printk("%s %d \n", __func__
, rc
);
500 return (rc
>= 0 && coredev
->postload_handler
) ?
501 coredev
->postload_handler(coredev
->context
) :
506 * loads specified firmware into a buffer and calls device loadfirmware_handler
508 * @param coredev pointer to a coredev object returned by smscore_register_device
509 * @param filename null-terminated string specifies firmware file name
510 * @param loadfirmware_handler device handler that loads firmware
512 * @return 0 on success, <0 on error.
514 int smscore_load_firmware(smscore_device_t
*coredev
, char* filename
, loadfirmware_t loadfirmware_handler
)
518 const struct firmware
*fw
;
521 if (loadfirmware_handler
== NULL
&& !(coredev
->device_flags
& SMS_DEVICE_FAMILY2
))
524 rc
= request_firmware(&fw
, filename
, coredev
->device
);
527 printk(KERN_INFO
"%s failed to open \"%s\"\n", __FUNCTION__
, filename
);
531 fw_buffer
= kmalloc(ALIGN(fw
->size
, SMS_ALLOC_ALIGNMENT
), GFP_KERNEL
| GFP_DMA
);
534 memcpy(fw_buffer
, fw
->data
, fw
->size
);
536 rc
= (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) ?
537 smscore_load_firmware_family2(coredev
, fw_buffer
, fw
->size
) :
538 loadfirmware_handler(coredev
->context
, fw_buffer
, fw
->size
);
544 printk(KERN_INFO
"%s failed to allocate firmware buffer\n", __FUNCTION__
);
548 release_firmware(fw
);
554 * notifies all clients registered with the device, notifies hotplugs, frees all buffers and coredev object
556 * @param coredev pointer to a coredev object returned by smscore_register_device
558 * @return 0 on success, <0 on error.
560 void smscore_unregister_device(smscore_device_t
*coredev
)
562 smscore_buffer_t
*cb
;
565 kmutex_lock(&g_smscore_deviceslock
);
567 smscore_notify_clients(coredev
);
568 smscore_notify_callbacks(coredev
, NULL
, 0);
570 // at this point all buffers should be back
571 // onresponse must no longer be called
575 while ((cb
= smscore_getbuffer(coredev
)))
581 if (num_buffers
== coredev
->num_buffers
)
584 printk(KERN_INFO
"%s waiting for %d buffer(s)\n", __FUNCTION__
, coredev
->num_buffers
- num_buffers
);
588 printk(KERN_INFO
"%s freed %d buffers\n", __FUNCTION__
, num_buffers
);
590 if (coredev
->common_buffer
)
591 dma_free_coherent(NULL
, coredev
->common_buffer_size
, coredev
->common_buffer
, coredev
->common_buffer_phys
);
593 list_del(&coredev
->entry
);
596 kmutex_unlock(&g_smscore_deviceslock
);
598 printk(KERN_INFO
"%s device %p destroyed\n", __FUNCTION__
, coredev
);
601 int smscore_detect_mode(smscore_device_t
*coredev
)
603 void *buffer
= kmalloc(sizeof(SmsMsgHdr_ST
) + SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
604 SmsMsgHdr_ST
*msg
= (SmsMsgHdr_ST
*) SMS_ALIGN_ADDRESS(buffer
);
610 SMS_INIT_MSG(msg
, MSG_SMS_GET_VERSION_EX_REQ
, sizeof(SmsMsgHdr_ST
));
612 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->version_ex_done
);
615 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed first try\n", __FUNCTION__
);
617 if (wait_for_completion_timeout(&coredev
->resume_done
, msecs_to_jiffies(5000)))
619 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->version_ex_done
);
622 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n", __FUNCTION__
, rc
);
634 char *smscore_fw_lkup
[] =
636 "dvb_nova_12mhz.inp",
637 "dvb_nova_12mhz.inp",
640 "dvb_nova_12mhz.inp",
641 "isdbt_nova_12mhz.inp",
642 "isdbt_nova_12mhz.inp",
643 "cmmb_nova_12mhz.inp",
648 * calls device handler to change mode of operation
649 * NOTE: stellar/usb may disconnect when changing mode
651 * @param coredev pointer to a coredev object returned by smscore_register_device
652 * @param mode requested mode of operation
654 * @return 0 on success, <0 on error.
656 int smscore_set_device_mode(smscore_device_t
*coredev
, int mode
)
661 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
)
663 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_RAW_TUNER
)
665 printk(KERN_INFO
"%s invalid mode specified %d\n", __FUNCTION__
, mode
);
669 if (!(coredev
->device_flags
& SMS_DEVICE_NOT_READY
))
671 rc
= smscore_detect_mode(coredev
);
676 if (coredev
->mode
== mode
)
678 printk(KERN_INFO
"%s device mode %d already set\n", __FUNCTION__
, mode
);
682 if (!(coredev
->modes_supported
& (1 << mode
)))
684 rc
= smscore_load_firmware(coredev
, smscore_fw_lkup
[mode
], NULL
);
690 printk(KERN_INFO
"%s mode %d supported by running firmware\n", __FUNCTION__
, mode
);
693 buffer
= kmalloc(sizeof(SmsMsgData_ST
) + SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
696 SmsMsgData_ST
*msg
= (SmsMsgData_ST
*) SMS_ALIGN_ADDRESS(buffer
);
698 SMS_INIT_MSG(&msg
->xMsgHeader
, MSG_SMS_INIT_DEVICE_REQ
, sizeof(SmsMsgData_ST
));
699 msg
->msgData
[0] = mode
;
701 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->xMsgHeader
.msgLength
, &coredev
->init_device_done
);
710 if (coredev
->detectmode_handler
)
711 coredev
->detectmode_handler(coredev
->context
, &coredev
->mode
);
713 if (coredev
->mode
!= mode
&& coredev
->setmode_handler
)
714 rc
= coredev
->setmode_handler(coredev
->context
, mode
);
717 smscore_registry_setmode(coredev
->devpath
, mode
);
721 coredev
->mode
= mode
;
722 coredev
->device_flags
&= ~SMS_DEVICE_NOT_READY
;
729 * calls device handler to get current mode of operation
731 * @param coredev pointer to a coredev object returned by smscore_register_device
733 * @return current mode
735 int smscore_get_device_mode(smscore_device_t
*coredev
)
737 return coredev
->mode
;
740 smscore_client_t
* smscore_getclient_by_type(smscore_device_t
*coredev
, int data_type
)
742 smscore_client_t
*client
= NULL
;
743 struct list_head
*next
, *first
;
749 spin_lock_irqsave(&coredev
->clientslock
, flags
);
751 first
= &coredev
->clients
;
753 for (next
= first
->next
; next
!= first
; next
= next
->next
)
755 if (((smscore_client_t
*) next
)->data_type
== data_type
)
757 client
= (smscore_client_t
*) next
;
762 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
767 smscore_client_t
* smscore_getclient_by_id(smscore_device_t
*coredev
, int id
)
769 smscore_client_t
*client
= NULL
;
770 struct list_head
*next
, *first
;
773 spin_lock_irqsave(&coredev
->clientslock
, flags
);
775 first
= &coredev
->subclients
;
777 for (next
= first
->next
; next
!= first
; next
= next
->next
)
779 if (((smscore_subclient_t
*) next
)->id
== id
)
781 client
= ((smscore_subclient_t
*) next
)->client
;
786 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
792 * find client by response id/type, call clients onresponse handler
793 * return buffer to pool on error
795 * @param coredev pointer to a coredev object returned by smscore_register_device
796 * @param cb pointer to response buffer descriptor
799 void smscore_onresponse(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
801 SmsMsgHdr_ST
*phdr
= (SmsMsgHdr_ST
*)((u8
*) cb
->p
+ cb
->offset
);
802 smscore_client_t
* client
= smscore_getclient_by_type(coredev
, phdr
->msgType
);
805 static unsigned long last_sample_time
= 0;
806 static int data_total
= 0;
807 unsigned long time_now
= jiffies_to_msecs(jiffies
);
809 if (!last_sample_time
)
810 last_sample_time
= time_now
;
812 if (time_now
- last_sample_time
> 10000)
814 printk("\n%s data rate %d bytes/secs\n", __func__
, (int)((data_total
* 1000) / (time_now
- last_sample_time
)));
816 last_sample_time
= time_now
;
820 data_total
+= cb
->size
;
823 client
= smscore_getclient_by_id(coredev
, phdr
->msgDstId
);
826 rc
= client
->onresponse_handler(client
->context
, cb
);
830 switch (phdr
->msgType
)
832 case MSG_SMS_GET_VERSION_EX_RES
:
834 SmsVersionRes_ST
*ver
= (SmsVersionRes_ST
*) phdr
;
835 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
);
837 coredev
->mode
= ver
->FirmwareId
== 255 ? DEVICE_MODE_NONE
: ver
->FirmwareId
;
838 coredev
->modes_supported
= ver
->SupportedProtocols
;
840 complete(&coredev
->version_ex_done
);
844 case MSG_SMS_INIT_DEVICE_RES
:
845 printk("%s: MSG_SMS_INIT_DEVICE_RES\n", __FUNCTION__
);
846 complete(&coredev
->init_device_done
);
849 case MSG_SW_RELOAD_START_RES
:
850 printk("%s: MSG_SW_RELOAD_START_RES\n", __FUNCTION__
);
851 complete(&coredev
->reload_start_done
);
854 case MSG_SMS_DATA_DOWNLOAD_RES
:
855 complete(&coredev
->data_download_done
);
858 case MSG_SW_RELOAD_EXEC_RES
:
859 printk("%s: MSG_SW_RELOAD_EXEC_RES\n", __FUNCTION__
);
862 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES
:
863 printk("%s: MSG_SMS_SWDOWNLOAD_TRIGGER_RES\n", __FUNCTION__
);
864 complete(&coredev
->trigger_done
);
867 case MSG_SMS_SLEEP_RESUME_COMP_IND
:
868 complete(&coredev
->resume_done
);
872 printk(KERN_INFO
"%s no client (%p) or error (%d), type:%d dstid:%d\n", __FUNCTION__
, client
, rc
, phdr
->msgType
, phdr
->msgDstId
);
875 smscore_putbuffer(coredev
, cb
);
880 * return pointer to next free buffer descriptor from core pool
882 * @param coredev pointer to a coredev object returned by smscore_register_device
884 * @return pointer to descriptor on success, NULL on error.
886 smscore_buffer_t
*smscore_getbuffer(smscore_device_t
*coredev
)
888 smscore_buffer_t
*cb
= NULL
;
891 spin_lock_irqsave(&coredev
->bufferslock
, flags
);
893 if (!list_empty(&coredev
->buffers
))
895 cb
= (smscore_buffer_t
*) coredev
->buffers
.next
;
896 list_del(&cb
->entry
);
899 spin_unlock_irqrestore(&coredev
->bufferslock
, flags
);
905 * return buffer descriptor to a pool
907 * @param coredev pointer to a coredev object returned by smscore_register_device
908 * @param cb pointer buffer descriptor
911 void smscore_putbuffer(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
913 list_add_locked(&cb
->entry
, &coredev
->buffers
, &coredev
->bufferslock
);
916 int smscore_validate_client(smscore_device_t
*coredev
, smscore_client_t
*client
, int id
)
918 smscore_client_t
*existing_client
;
919 smscore_subclient_t
*subclient
;
924 existing_client
= smscore_getclient_by_id(coredev
, id
);
925 if (existing_client
== client
)
931 subclient
= kzalloc(sizeof(smscore_subclient_t
), GFP_KERNEL
);
935 subclient
->client
= client
;
938 list_add_locked(&subclient
->entry
, &coredev
->subclients
, &coredev
->clientslock
);
944 * creates smsclient object, check that id is taken by another client
946 * @param coredev pointer to a coredev object from clients hotplug
947 * @param initial_id all messages with this id would be sent to this client
948 * @param data_type all messages of this type would be sent to this client
949 * @param onresponse_handler client handler that is called to process incoming messages
950 * @param onremove_handler client handler that is called when device is removed
951 * @param context client-specific context
952 * @param client pointer to a value that receives created smsclient object
954 * @return 0 on success, <0 on error.
956 int smscore_register_client(smscore_device_t
*coredev
, smsclient_params_t
*params
, smscore_client_t
**client
)
958 smscore_client_t
* newclient
;
961 // check that no other channel with same data type exists
962 if (params
->data_type
&& smscore_getclient_by_type(coredev
, params
->data_type
))
965 newclient
= kzalloc(sizeof(smscore_client_t
), GFP_KERNEL
);
969 // check that no other channel with same id exists
970 rc
= smscore_validate_client(coredev
, newclient
, params
->initial_id
);
977 newclient
->coredev
= coredev
;
978 newclient
->data_type
= params
->data_type
;
979 newclient
->onresponse_handler
= params
->onresponse_handler
;
980 newclient
->onremove_handler
= params
->onremove_handler
;
981 newclient
->context
= params
->context
;
983 list_add_locked(&newclient
->entry
, &coredev
->clients
, &coredev
->clientslock
);
987 printk(KERN_INFO
"%s %p %d %d\n", __FUNCTION__
, params
->context
, params
->data_type
, params
->initial_id
);
993 * frees smsclient object and all subclients associated with it
995 * @param client pointer to smsclient object returned by smscore_register_client
998 void smscore_unregister_client(smscore_client_t
*client
)
1000 smscore_device_t
*coredev
= client
->coredev
;
1001 struct list_head
*next
, *first
;
1002 unsigned long flags
;
1004 spin_lock_irqsave(&coredev
->clientslock
, flags
);
1006 first
= &coredev
->subclients
;
1008 for (next
= first
->next
; next
!= first
;)
1010 smscore_subclient_t
*subclient
= (smscore_subclient_t
*) next
;
1013 if (subclient
->client
== client
)
1015 list_del(&subclient
->entry
);
1020 printk(KERN_INFO
"%s %p %d\n", __FUNCTION__
, client
->context
, client
->data_type
);
1022 list_del(&client
->entry
);
1025 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
1029 * verifies that source id is not taken by another client,
1030 * calls device handler to send requests to the device
1032 * @param client pointer to smsclient object returned by smscore_register_client
1033 * @param buffer pointer to a request buffer
1034 * @param size size (in bytes) of request buffer
1036 * @return 0 on success, <0 on error.
1038 int smsclient_sendrequest(smscore_client_t
*client
, void *buffer
, size_t size
)
1040 smscore_device_t
* coredev
= client
->coredev
;
1041 SmsMsgHdr_ST
* phdr
= (SmsMsgHdr_ST
*) buffer
;
1043 // check that no other channel with same id exists
1044 int rc
= smscore_validate_client(client
->coredev
, client
, phdr
->msgSrcId
);
1048 return coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
1052 * return the size of large (common) buffer
1054 * @param coredev pointer to a coredev object from clients hotplug
1056 * @return size (in bytes) of the buffer
1058 int smscore_get_common_buffer_size(smscore_device_t
*coredev
)
1060 return coredev
->common_buffer_size
;
1064 * maps common buffer (if supported by platform)
1066 * @param coredev pointer to a coredev object from clients hotplug
1067 * @param vma pointer to vma struct from mmap handler
1069 * @return 0 on success, <0 on error.
1071 int smscore_map_common_buffer(smscore_device_t
*coredev
, struct vm_area_struct
* vma
)
1073 unsigned long end
= vma
->vm_end
, start
= vma
->vm_start
, size
= PAGE_ALIGN(coredev
->common_buffer_size
);
1075 if (!(vma
->vm_flags
& (VM_READ
| VM_SHARED
)) || (vma
->vm_flags
& VM_WRITE
))
1077 printk(KERN_INFO
"%s invalid vm flags\n", __FUNCTION__
);
1081 if ((end
- start
) != size
)
1083 printk(KERN_INFO
"%s invalid size %d expected %d\n", __FUNCTION__
, (int)(end
- start
), (int) size
);
1087 if (remap_pfn_range(vma
, start
, coredev
->common_buffer_phys
>> PAGE_SHIFT
, size
, pgprot_noncached(vma
->vm_page_prot
)))
1089 printk(KERN_INFO
"%s remap_page_range failed\n", __FUNCTION__
);
1096 int smscore_module_init(void)
1100 INIT_LIST_HEAD(&g_smscore_notifyees
);
1101 INIT_LIST_HEAD(&g_smscore_devices
);
1102 kmutex_init(&g_smscore_deviceslock
);
1104 INIT_LIST_HEAD(&g_smscore_registry
);
1105 kmutex_init(&g_smscore_registrylock
);
1108 rc
= smsusb_register();
1111 rc
= smsdvb_register();
1113 printk(KERN_INFO
"%s, rc %d\n", __FUNCTION__
, rc
);
1118 void smscore_module_exit(void)
1121 kmutex_lock(&g_smscore_deviceslock
);
1122 while (!list_empty(&g_smscore_notifyees
))
1124 smscore_device_notifyee_t
*notifyee
= (smscore_device_notifyee_t
*) g_smscore_notifyees
.next
;
1126 list_del(¬ifyee
->entry
);
1129 kmutex_unlock(&g_smscore_deviceslock
);
1131 kmutex_lock(&g_smscore_registrylock
);
1132 while (!list_empty(&g_smscore_registry
))
1134 smscore_registry_entry_t
*entry
= (smscore_registry_entry_t
*) g_smscore_registry
.next
;
1136 list_del(&entry
->entry
);
1139 kmutex_unlock(&g_smscore_registrylock
);
1141 /* DVB UnRegister */
1142 smsdvb_unregister();
1144 /* Unregister USB */
1145 smsusb_unregister();
1147 printk(KERN_INFO
"%s\n", __FUNCTION__
);
1150 module_init(smscore_module_init
);
1151 module_exit(smscore_module_exit
);
1153 MODULE_DESCRIPTION("smscore");
1154 MODULE_AUTHOR("Anatoly Greenblatt,,, (anatolyg@siano-ms.com)");
1155 MODULE_LICENSE("GPL");
1157 EXPORT_SYMBOL(smscore_registry_setmode
);
1158 EXPORT_SYMBOL(smscore_registry_getmode
);
1159 EXPORT_SYMBOL(smscore_register_hotplug
);
1160 EXPORT_SYMBOL(smscore_unregister_hotplug
);
1161 EXPORT_SYMBOL(smscore_register_device
);
1162 EXPORT_SYMBOL(smscore_unregister_device
);
1163 EXPORT_SYMBOL(smscore_start_device
);
1164 EXPORT_SYMBOL(smscore_load_firmware
);
1165 EXPORT_SYMBOL(smscore_set_device_mode
);
1166 EXPORT_SYMBOL(smscore_get_device_mode
);
1167 EXPORT_SYMBOL(smscore_register_client
);
1168 EXPORT_SYMBOL(smscore_unregister_client
);
1169 EXPORT_SYMBOL(smsclient_sendrequest
);
1170 EXPORT_SYMBOL(smscore_onresponse
);
1171 EXPORT_SYMBOL(smscore_get_common_buffer_size
);
1172 EXPORT_SYMBOL(smscore_map_common_buffer
);
1173 EXPORT_SYMBOL(smscore_getbuffer
);
1174 EXPORT_SYMBOL(smscore_putbuffer
);