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"
36 #define PERROR(fmt, args...)\
37 printk(KERN_ERR "smscore error: line %d- %s(): " fmt, \
38 __LINE__, __func__, ## args)
42 # define PWARNING(fmt, args...) printk(KERN_INFO "smscore warning: " \
43 "line %d- %s(): " fmt, \
44 __LINE__, __func__, ## args)
45 #undef PDEBUG /* undef it, just in case */
46 # define PDEBUG(fmt, args...) printk(KERN_INFO "smscore - %s(): " fmt, \
48 #else /*SMSCORE_DEBUG*/
49 #define PDEBUG(fmt, args...)
50 #define PWARNING(fmt, args...)
53 typedef struct _smscore_device_notifyee
55 struct list_head entry
;
57 } smscore_device_notifyee_t
;
59 typedef struct _smscore_subclient
61 struct list_head entry
;
66 typedef struct _smscore_client
68 struct list_head entry
;
69 smscore_device_t
*coredev
;
71 struct list_head idlist
;
72 onresponse_t onresponse_handler
;
73 onremove_t onremove_handler
;
78 typedef struct _smscore_device
80 struct list_head entry
;
82 struct list_head clients
;
83 struct list_head subclients
;
84 spinlock_t clientslock
;
86 struct list_head buffers
;
87 spinlock_t bufferslock
;
91 int common_buffer_size
;
92 dma_addr_t common_buffer_phys
;
95 struct device
*device
;
98 unsigned long device_flags
;
100 setmode_t setmode_handler
;
101 detectmode_t detectmode_handler
;
102 sendrequest_t sendrequest_handler
;
103 preload_t preload_handler
;
104 postload_t postload_handler
;
106 int mode
, modes_supported
;
108 struct completion version_ex_done
, data_download_done
, trigger_done
;
109 struct completion init_device_done
, reload_start_done
, resume_done
;
110 } *psmscore_device_t
;
112 typedef struct _smscore_registry_entry
114 struct list_head entry
;
117 sms_device_type_st type
;
118 } smscore_registry_entry_t
;
120 struct list_head g_smscore_notifyees
;
121 struct list_head g_smscore_devices
;
122 kmutex_t g_smscore_deviceslock
;
124 struct list_head g_smscore_registry
;
125 kmutex_t g_smscore_registrylock
;
127 static int default_mode
= 1;
129 module_param(default_mode
, int, 0644);
130 MODULE_PARM_DESC(default_mode
, "default firmware id (device mode)");
132 static smscore_registry_entry_t
*smscore_find_registry(char *devpath
)
134 smscore_registry_entry_t
*entry
;
135 struct list_head
*next
;
137 kmutex_lock(&g_smscore_registrylock
);
138 for (next
= g_smscore_registry
.next
;
139 next
!= &g_smscore_registry
;
141 entry
= (smscore_registry_entry_t
*) next
;
142 if (!strcmp(entry
->devpath
, devpath
)) {
143 kmutex_unlock(&g_smscore_registrylock
);
147 entry
= (smscore_registry_entry_t
*)
148 kmalloc(sizeof(smscore_registry_entry_t
), GFP_KERNEL
);
150 entry
->mode
= default_mode
;
151 strcpy(entry
->devpath
, devpath
);
152 list_add(&entry
->entry
, &g_smscore_registry
);
154 printk(KERN_ERR
"%s failed to create smscore_registry.\n",
156 kmutex_unlock(&g_smscore_registrylock
);
160 int smscore_registry_getmode(char *devpath
)
162 smscore_registry_entry_t
*entry
;
164 entry
= smscore_find_registry(devpath
);
168 printk(KERN_ERR
"%s No registry found.\n", __func__
);
173 sms_device_type_st
smscore_registry_gettype(char *devpath
)
175 smscore_registry_entry_t
*entry
;
177 entry
= smscore_find_registry(devpath
);
181 printk(KERN_ERR
"%s No registry found.\n", __func__
);
186 void smscore_registry_setmode(char *devpath
, int mode
)
188 smscore_registry_entry_t
*entry
;
190 entry
= smscore_find_registry(devpath
);
194 printk(KERN_ERR
"%s No registry found.\n", __func__
);
197 void smscore_registry_settype(char *devpath
, sms_device_type_st type
)
199 smscore_registry_entry_t
*entry
;
201 entry
= smscore_find_registry(devpath
);
205 printk(KERN_ERR
"%s No registry found.\n", __func__
);
210 void list_add_locked(struct list_head
*new, struct list_head
*head
,
215 spin_lock_irqsave(lock
, flags
);
219 spin_unlock_irqrestore(lock
, flags
);
223 * register a client callback that called when device plugged in/unplugged
224 * NOTE: if devices exist callback is called immediately for each device
226 * @param hotplug callback
228 * @return 0 on success, <0 on error.
230 int smscore_register_hotplug(hotplug_t hotplug
)
232 smscore_device_notifyee_t
*notifyee
;
233 struct list_head
*next
, *first
;
236 kmutex_lock(&g_smscore_deviceslock
);
238 notifyee
= kmalloc(sizeof(smscore_device_notifyee_t
), GFP_KERNEL
);
240 /* now notify callback about existing devices */
241 first
= &g_smscore_devices
;
242 for (next
= first
->next
;
243 next
!= first
&& !rc
;
245 smscore_device_t
*coredev
= (smscore_device_t
*) next
;
246 rc
= hotplug(coredev
, coredev
->device
, 1);
250 notifyee
->hotplug
= hotplug
;
251 list_add(¬ifyee
->entry
, &g_smscore_notifyees
);
257 kmutex_unlock(&g_smscore_deviceslock
);
263 * unregister a client callback that called when device plugged in/unplugged
265 * @param hotplug callback
268 void smscore_unregister_hotplug(hotplug_t hotplug
)
270 struct list_head
*next
, *first
;
272 kmutex_lock(&g_smscore_deviceslock
);
274 first
= &g_smscore_notifyees
;
276 for (next
= first
->next
; next
!= first
;) {
277 smscore_device_notifyee_t
*notifyee
=
278 (smscore_device_notifyee_t
*) next
;
281 if (notifyee
->hotplug
== hotplug
) {
282 list_del(¬ifyee
->entry
);
287 kmutex_unlock(&g_smscore_deviceslock
);
290 void smscore_notify_clients(smscore_device_t
*coredev
)
292 smscore_client_t
*client
;
294 /* the client must call smscore_unregister_client from remove handler */
295 while (!list_empty(&coredev
->clients
)) {
296 client
= (smscore_client_t
*) coredev
->clients
.next
;
297 client
->onremove_handler(client
->context
);
301 int smscore_notify_callbacks(smscore_device_t
*coredev
, struct device
*device
,
304 struct list_head
*next
, *first
;
307 /* note: must be called under g_deviceslock */
309 first
= &g_smscore_notifyees
;
311 for (next
= first
->next
; next
!= first
; next
= next
->next
) {
312 rc
= ((smscore_device_notifyee_t
*) next
)->hotplug(coredev
, device
, arrival
);
320 smscore_buffer_t
*smscore_createbuffer(u8
*buffer
, void *common_buffer
,
321 dma_addr_t common_buffer_phys
)
323 smscore_buffer_t
*cb
= kmalloc(sizeof(smscore_buffer_t
), GFP_KERNEL
);
325 printk(KERN_INFO
"%s kmalloc(...) failed\n", __func__
);
330 cb
->offset_in_common
= buffer
- (u8
*) common_buffer
;
331 cb
->phys
= common_buffer_phys
+ cb
->offset_in_common
;
337 * creates coredev object for a device, prepares buffers,
338 * creates buffer mappings, notifies registered hotplugs about new device.
340 * @param params device pointer to struct with device specific parameters and handlers
341 * @param coredev pointer to a value that receives created coredev object
343 * @return 0 on success, <0 on error.
345 int smscore_register_device(smsdevice_params_t
*params
,
346 smscore_device_t
**coredev
)
348 smscore_device_t
*dev
;
351 dev
= kzalloc(sizeof(smscore_device_t
), GFP_KERNEL
);
353 printk(KERN_INFO
"%s kzalloc(...) failed\n", __func__
);
357 /* init list entry so it could be safe in smscore_unregister_device */
358 INIT_LIST_HEAD(&dev
->entry
);
361 INIT_LIST_HEAD(&dev
->clients
);
362 INIT_LIST_HEAD(&dev
->buffers
);
365 spin_lock_init(&dev
->clientslock
);
366 spin_lock_init(&dev
->bufferslock
);
368 /* init completion events */
369 init_completion(&dev
->version_ex_done
);
370 init_completion(&dev
->data_download_done
);
371 init_completion(&dev
->trigger_done
);
372 init_completion(&dev
->init_device_done
);
373 init_completion(&dev
->reload_start_done
);
374 init_completion(&dev
->resume_done
);
376 /* alloc common buffer */
377 dev
->common_buffer_size
= params
->buffer_size
* params
->num_buffers
;
378 dev
->common_buffer
= dma_alloc_coherent(NULL
, dev
->common_buffer_size
,
379 &dev
->common_buffer_phys
,
380 GFP_KERNEL
| GFP_DMA
);
381 if (!dev
->common_buffer
) {
382 smscore_unregister_device(dev
);
386 /* prepare dma buffers */
387 for (buffer
= dev
->common_buffer
;
388 dev
->num_buffers
< params
->num_buffers
;
389 dev
->num_buffers
++, buffer
+= params
->buffer_size
) {
390 smscore_buffer_t
*cb
= smscore_createbuffer(buffer
, dev
->common_buffer
, dev
->common_buffer_phys
);
392 smscore_unregister_device(dev
);
396 smscore_putbuffer(dev
, cb
);
399 printk(KERN_INFO
"%s allocated %d buffers\n",
400 __func__
, 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 printk(KERN_INFO
"%s device %p created\n", __func__
, dev
);
429 * sets initial device mode and notifies client hotplugs that device is ready
431 * @param coredev pointer to a coredev object returned by smscore_register_device
433 * @return 0 on success, <0 on error.
435 int smscore_start_device(smscore_device_t
*coredev
)
437 int rc
= smscore_set_device_mode(coredev
, smscore_registry_getmode(coredev
->devpath
));
439 printk(KERN_INFO
"%s set device mode faile , rc %d\n", __func__
, rc
);
443 kmutex_lock(&g_smscore_deviceslock
);
445 rc
= smscore_notify_callbacks(coredev
, coredev
->device
, 1);
447 printk(KERN_INFO
"%s device %p started, rc %d\n",
448 __func__
, coredev
, rc
);
450 kmutex_unlock(&g_smscore_deviceslock
);
455 int smscore_sendrequest_and_wait(smscore_device_t
*coredev
, void *buffer
,
456 size_t size
, struct completion
*completion
)
458 int rc
= coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
460 printk(KERN_INFO
"%s sendrequest returned error %d\n",
465 return wait_for_completion_timeout(completion
,
466 msecs_to_jiffies(10000)) ?
470 int smscore_load_firmware_family2(smscore_device_t
*coredev
, void *buffer
,
473 SmsFirmware_ST
*firmware
= (SmsFirmware_ST
*) buffer
;
475 UINT32 mem_address
= firmware
->StartAddress
;
476 u8
*payload
= firmware
->Payload
;
479 printk(KERN_INFO
"%s loading FW to addr 0x%x size %d\n",
480 __func__
, mem_address
, firmware
->Length
);
481 if (coredev
->preload_handler
) {
482 rc
= coredev
->preload_handler(coredev
->context
);
487 /* PAGE_SIZE buffer shall be enough and dma aligned */
488 msg
= (SmsMsgHdr_ST
*) kmalloc(PAGE_SIZE
, GFP_KERNEL
| GFP_DMA
);
492 if (coredev
->mode
!= DEVICE_MODE_NONE
) {
493 PDEBUG("Sending reload command\n");
494 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_START_REQ
,
495 sizeof(SmsMsgHdr_ST
));
496 rc
= smscore_sendrequest_and_wait(coredev
, msg
,
498 &coredev
->reload_start_done
);
499 mem_address
= *(UINT32
*) &payload
[20];
502 while (size
&& rc
>= 0)
504 SmsDataDownload_ST
*DataMsg
= (SmsDataDownload_ST
*) msg
;
505 int payload_size
= min((int) size
, SMS_MAX_PAYLOAD_SIZE
);
507 SMS_INIT_MSG(msg
, MSG_SMS_DATA_DOWNLOAD_REQ
,
508 (UINT16
)(sizeof(SmsMsgHdr_ST
) +
509 sizeof(UINT32
) + payload_size
));
511 DataMsg
->MemAddr
= mem_address
;
512 memcpy(DataMsg
->Payload
, payload
, payload_size
);
514 if ((coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) &&
515 (coredev
->mode
== DEVICE_MODE_NONE
))
516 rc
= coredev
->sendrequest_handler(coredev
->context
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
);
518 rc
= smscore_sendrequest_and_wait(coredev
, DataMsg
, DataMsg
->xMsgHeader
.msgLength
, &coredev
->data_download_done
);
520 payload
+= payload_size
;
521 size
-= payload_size
;
522 mem_address
+= payload_size
;
526 if (coredev
->mode
== DEVICE_MODE_NONE
) {
527 SmsMsgData_ST
*TriggerMsg
= (SmsMsgData_ST
*) msg
;
529 SMS_INIT_MSG(msg
, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ
,
530 sizeof(SmsMsgHdr_ST
) +
533 TriggerMsg
->msgData
[0] = firmware
->StartAddress
; // Entry point
534 TriggerMsg
->msgData
[1] = 5; // Priority
535 TriggerMsg
->msgData
[2] = 0x200; // Stack size
536 TriggerMsg
->msgData
[3] = 0; // Parameter
537 TriggerMsg
->msgData
[4] = 4; // Task ID
539 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) {
540 rc
= coredev
->sendrequest_handler(coredev
->context
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
);
543 rc
= smscore_sendrequest_and_wait(coredev
, TriggerMsg
, TriggerMsg
->xMsgHeader
.msgLength
, &coredev
->trigger_done
);
545 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_EXEC_REQ
,
546 sizeof(SmsMsgHdr_ST
));
548 rc
= coredev
->sendrequest_handler(coredev
->context
,
549 msg
, msg
->msgLength
);
554 printk("%s rc=%d, postload=%p \n", __func__
, rc
,
555 coredev
->postload_handler
);
559 return ((rc
>= 0) && coredev
->postload_handler
) ?
560 coredev
->postload_handler(coredev
->context
) :
565 * loads specified firmware into a buffer and calls device loadfirmware_handler
567 * @param coredev pointer to a coredev object returned by smscore_register_device
568 * @param filename null-terminated string specifies firmware file name
569 * @param loadfirmware_handler device handler that loads firmware
571 * @return 0 on success, <0 on error.
573 int smscore_load_firmware_from_file(smscore_device_t
*coredev
, char *filename
,
574 loadfirmware_t loadfirmware_handler
)
578 const struct firmware
*fw
;
581 if (loadfirmware_handler
== NULL
&& !(coredev
->device_flags
&
585 rc
= request_firmware(&fw
, filename
, coredev
->device
);
587 printk(KERN_INFO
"%s failed to open \"%s\"\n",
591 printk(KERN_INFO
"%s read FW %s, size=%d\"\n", __func__
,
593 fw_buffer
= kmalloc(ALIGN(fw
->size
, SMS_ALLOC_ALIGNMENT
),
594 GFP_KERNEL
| GFP_DMA
);
596 memcpy(fw_buffer
, fw
->data
, fw
->size
);
598 rc
= (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) ?
599 smscore_load_firmware_family2(coredev
, fw_buffer
, fw
->size
) :
600 loadfirmware_handler(coredev
->context
, fw_buffer
, fw
->size
);
604 printk(KERN_INFO
"%s failed to allocate firmware buffer\n",
609 release_firmware(fw
);
614 int smscore_load_firmware_from_buffer(smscore_device_t
*coredev
, u8
*buffer
,
615 int size
, int new_mode
)
617 PERROR("Feature not implemented yet\n");
622 * notifies all clients registered with the device, notifies hotplugs, frees all buffers and coredev object
624 * @param coredev pointer to a coredev object returned by smscore_register_device
626 * @return 0 on success, <0 on error.
628 void smscore_unregister_device(smscore_device_t
*coredev
)
630 smscore_buffer_t
*cb
;
634 kmutex_lock(&g_smscore_deviceslock
);
636 smscore_notify_clients(coredev
);
637 smscore_notify_callbacks(coredev
, NULL
, 0);
639 /* at this point all buffers should be back
640 * onresponse must no longer be called */
643 while ((cb
= smscore_getbuffer(coredev
))) {
647 if (num_buffers
== coredev
->num_buffers
)
650 printk(KERN_INFO
"%s exiting although "
651 "not all buffers released.\n", __func__
);
655 printk(KERN_INFO
"%s waiting for %d buffer(s)\n", __func__
,
656 coredev
->num_buffers
- num_buffers
);
660 printk(KERN_INFO
"%s freed %d buffers\n", __func__
, num_buffers
);
662 if (coredev
->common_buffer
)
663 dma_free_coherent(NULL
, coredev
->common_buffer_size
,
664 coredev
->common_buffer
,
665 coredev
->common_buffer_phys
);
667 list_del(&coredev
->entry
);
670 kmutex_unlock(&g_smscore_deviceslock
);
672 printk(KERN_INFO
"%s device %p destroyed\n", __func__
, coredev
);
675 int smscore_detect_mode(smscore_device_t
*coredev
)
677 void *buffer
= kmalloc(sizeof(SmsMsgHdr_ST
) + SMS_DMA_ALIGNMENT
,
678 GFP_KERNEL
| GFP_DMA
);
679 SmsMsgHdr_ST
*msg
= (SmsMsgHdr_ST
*) SMS_ALIGN_ADDRESS(buffer
);
685 SMS_INIT_MSG(msg
, MSG_SMS_GET_VERSION_EX_REQ
, sizeof(SmsMsgHdr_ST
));
687 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
,
688 &coredev
->version_ex_done
);
690 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed first try\n", __func__
);
692 if (wait_for_completion_timeout(&coredev
->resume_done
,
693 msecs_to_jiffies(5000))) {
694 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
, &coredev
->version_ex_done
);
696 printk("%s: MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n", __func__
, rc
);
706 char *smscore_fw_lkup
[][SMS_NUM_OF_DEVICE_TYPES
] = {
707 /*Stellar NOVA A0 Nova B0 VEGA*/
708 /*DVBT*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
709 /*DVBH*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
710 /*TDMB*/ {"none", "tdmb_nova_12mhz.inp", "none", "none"},
711 /*DABIP*/ {"none", "none", "none", "none"},
712 /*BDA*/ {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
713 /*ISDBT*/ {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
714 /*ISDBTBDA*/{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
715 /*CMMB*/ {"none", "none", "none", "cmmb_vega_12mhz.inp"}
720 * calls device handler to change mode of operation
721 * NOTE: stellar/usb may disconnect when changing mode
723 * @param coredev pointer to a coredev object returned by smscore_register_device
724 * @param mode requested mode of operation
726 * @return 0 on success, <0 on error.
728 int smscore_set_device_mode(smscore_device_t
*coredev
, int mode
)
732 sms_device_type_st type
;
734 PDEBUG("set device mode to %d\n", mode
);
735 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) {
736 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_RAW_TUNER
) {
737 printk(KERN_INFO
"%s invalid mode specified %d\n",
742 smscore_registry_setmode(coredev
->devpath
, mode
);
744 if (!(coredev
->device_flags
& SMS_DEVICE_NOT_READY
)) {
745 rc
= smscore_detect_mode(coredev
);
747 printk(KERN_INFO
"%s mode detect failed %d\n",
753 if (coredev
->mode
== mode
) {
754 printk(KERN_INFO
"%s device mode %d already set\n",
759 if (!(coredev
->modes_supported
& (1 << mode
))) {
760 type
= smscore_registry_gettype(coredev
->devpath
);
761 rc
= smscore_load_firmware_from_file(coredev
, smscore_fw_lkup
[mode
][type
], NULL
);
763 printk(KERN_INFO
"%s load firmware failed %d\n", __func__
, rc
);
767 printk(KERN_INFO
"%s mode %d supported by running firmware\n", __func__
, mode
);
769 buffer
= kmalloc(sizeof(SmsMsgData_ST
) + SMS_DMA_ALIGNMENT
,
770 GFP_KERNEL
| GFP_DMA
);
772 SmsMsgData_ST
*msg
= (SmsMsgData_ST
*) SMS_ALIGN_ADDRESS(buffer
);
774 SMS_INIT_MSG(&msg
->xMsgHeader
, MSG_SMS_INIT_DEVICE_REQ
, sizeof(SmsMsgData_ST
));
775 msg
->msgData
[0] = mode
;
777 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->xMsgHeader
.msgLength
, &coredev
->init_device_done
);
781 printk(KERN_INFO
"%s Could not allocate buffer for init device message.\n", __func__
);
785 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_DVBT_BDA
) {
786 printk(KERN_INFO
"%s invalid mode specified %d\n",
791 smscore_registry_setmode(coredev
->devpath
, mode
);
793 if (coredev
->detectmode_handler
)
794 coredev
->detectmode_handler(coredev
->context
,
797 if (coredev
->mode
!= mode
&& coredev
->setmode_handler
)
798 rc
= coredev
->setmode_handler(coredev
->context
, mode
);
802 coredev
->mode
= mode
;
803 coredev
->device_flags
&= ~SMS_DEVICE_NOT_READY
;
807 printk(KERN_INFO
"%s return error code %d.\n", __func__
, rc
);
812 * calls device handler to get current mode of operation
814 * @param coredev pointer to a coredev object returned by smscore_register_device
816 * @return current mode
818 int smscore_get_device_mode(smscore_device_t
*coredev
)
820 return coredev
->mode
;
824 * find client by response id & type within the clients list.
825 * return client handle or NULL.
827 * @param coredev pointer to a coredev object returned by smscore_register_device
828 * @param data_type client data type (SMS_DONT_CARE for all types)
829 * @param id client id (SMS_DONT_CARE for all id)
832 smscore_client_t
*smscore_find_client(smscore_device_t
*coredev
, int data_type
, int id
)
834 smscore_client_t
*client
= NULL
;
835 struct list_head
*next
, *first
;
837 struct list_head
*firstid
, *nextid
;
840 spin_lock_irqsave(&coredev
->clientslock
, flags
);
841 first
= &coredev
->clients
;
842 for (next
= first
->next
;
843 (next
!= first
) && !client
;
845 firstid
= &((smscore_client_t
*)next
)->idlist
;
846 for (nextid
= firstid
->next
;
848 nextid
= nextid
->next
) {
849 if ((((smscore_idlist_t
*)nextid
)->id
== id
) &&
850 (((smscore_idlist_t
*)nextid
)->data_type
== data_type
||
851 (((smscore_idlist_t
*)nextid
)->data_type
== 0))) {
852 client
= (smscore_client_t
*) next
;
857 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
862 * find client by response id/type, call clients onresponse handler
863 * return buffer to pool on error
865 * @param coredev pointer to a coredev object returned by smscore_register_device
866 * @param cb pointer to response buffer descriptor
869 void smscore_onresponse(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
871 SmsMsgHdr_ST
*phdr
= (SmsMsgHdr_ST
*)((u8
*) cb
->p
+ cb
->offset
);
872 smscore_client_t
*client
= smscore_find_client(coredev
, phdr
->msgType
,
876 static unsigned long last_sample_time
= 0;
877 static int data_total
= 0;
878 unsigned long time_now
= jiffies_to_msecs(jiffies
);
880 if (!last_sample_time
)
881 last_sample_time
= time_now
;
883 if (time_now
- last_sample_time
> 10000)
885 printk("\n%s data rate %d bytes/secs\n", __func__
,
886 (int)((data_total
* 1000) /
887 (time_now
- last_sample_time
)));
889 last_sample_time
= time_now
;
893 data_total
+= cb
->size
;
894 /* If no client registered for type & id,
895 * check for control client where type is not registered */
897 rc
= client
->onresponse_handler(client
->context
, cb
);
900 switch (phdr
->msgType
) {
901 case MSG_SMS_GET_VERSION_EX_RES
:
903 SmsVersionRes_ST
*ver
= (SmsVersionRes_ST
*) phdr
;
904 printk("%s: MSG_SMS_GET_VERSION_EX_RES id %d "
905 "prots 0x%x ver %d.%d\n", __func__
,
906 ver
->FirmwareId
, ver
->SupportedProtocols
,
907 ver
->RomVersionMajor
, ver
->RomVersionMinor
);
909 coredev
->mode
= ver
->FirmwareId
== 255 ?
910 DEVICE_MODE_NONE
: ver
->FirmwareId
;
911 coredev
->modes_supported
= ver
->SupportedProtocols
;
913 complete(&coredev
->version_ex_done
);
916 case MSG_SMS_INIT_DEVICE_RES
:
917 printk("%s: MSG_SMS_INIT_DEVICE_RES\n", __func__
);
918 complete(&coredev
->init_device_done
);
920 case MSG_SW_RELOAD_START_RES
:
921 printk("%s: MSG_SW_RELOAD_START_RES\n", __func__
);
922 complete(&coredev
->reload_start_done
);
924 case MSG_SMS_DATA_DOWNLOAD_RES
:
925 complete(&coredev
->data_download_done
);
927 case MSG_SW_RELOAD_EXEC_RES
:
928 printk("%s: MSG_SW_RELOAD_EXEC_RES\n", __func__
);
930 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES
:
931 printk("%s: MSG_SMS_SWDOWNLOAD_TRIGGER_RES\n",
933 complete(&coredev
->trigger_done
);
935 case MSG_SMS_SLEEP_RESUME_COMP_IND
:
936 complete(&coredev
->resume_done
);
941 smscore_putbuffer(coredev
, cb
);
946 * return pointer to next free buffer descriptor from core pool
948 * @param coredev pointer to a coredev object returned by smscore_register_device
950 * @return pointer to descriptor on success, NULL on error.
952 smscore_buffer_t
*smscore_getbuffer(smscore_device_t
*coredev
)
954 smscore_buffer_t
*cb
= NULL
;
957 spin_lock_irqsave(&coredev
->bufferslock
, flags
);
959 if (!list_empty(&coredev
->buffers
)) {
960 cb
= (smscore_buffer_t
*) coredev
->buffers
.next
;
961 list_del(&cb
->entry
);
964 spin_unlock_irqrestore(&coredev
->bufferslock
, flags
);
970 * return buffer descriptor to a pool
972 * @param coredev pointer to a coredev object returned by smscore_register_device
973 * @param cb pointer buffer descriptor
976 void smscore_putbuffer(smscore_device_t
*coredev
, smscore_buffer_t
*cb
)
978 list_add_locked(&cb
->entry
, &coredev
->buffers
, &coredev
->bufferslock
);
981 int smscore_validate_client(smscore_device_t
*coredev
,
982 smscore_client_t
*client
, int data_type
, int id
)
984 smscore_idlist_t
*listentry
;
985 smscore_client_t
*registered_client
;
988 PERROR("bad parameter.\n");
991 registered_client
= smscore_find_client(coredev
, data_type
, id
);
992 if (registered_client
== client
) {
995 if (registered_client
) {
996 PERROR("The msg ID already registered to another client.\n");
999 listentry
= kzalloc(sizeof(smscore_idlist_t
), GFP_KERNEL
);
1001 PERROR("Can't allocate memory for client id.\n");
1005 listentry
->data_type
= data_type
;
1006 list_add_locked(&listentry
->entry
, &client
->idlist
,
1007 &coredev
->clientslock
);
1012 * creates smsclient object, check that id is taken by another client
1014 * @param coredev pointer to a coredev object from clients hotplug
1015 * @param initial_id all messages with this id would be sent to this client
1016 * @param data_type all messages of this type would be sent to this client
1017 * @param onresponse_handler client handler that is called to process incoming messages
1018 * @param onremove_handler client handler that is called when device is removed
1019 * @param context client-specific context
1020 * @param client pointer to a value that receives created smsclient object
1022 * @return 0 on success, <0 on error.
1024 int smscore_register_client(smscore_device_t
*coredev
, smsclient_params_t
*params
, smscore_client_t
**client
)
1026 smscore_client_t
*newclient
;
1027 /* check that no other channel with same parameters exists */
1028 if (smscore_find_client(coredev
, params
->data_type
,
1029 params
->initial_id
)) {
1030 PERROR("Client already exist.\n");
1034 newclient
= kzalloc(sizeof(smscore_client_t
), GFP_KERNEL
);
1036 PERROR("Failed to allocate memory for client.\n");
1040 INIT_LIST_HEAD(&newclient
->idlist
);
1041 newclient
->coredev
= coredev
;
1042 newclient
->onresponse_handler
= params
->onresponse_handler
;
1043 newclient
->onremove_handler
= params
->onremove_handler
;
1044 newclient
->context
= params
->context
;
1045 list_add_locked(&newclient
->entry
, &coredev
->clients
,
1046 &coredev
->clientslock
);
1047 smscore_validate_client(coredev
, newclient
, params
->data_type
,
1048 params
->initial_id
);
1049 *client
= newclient
;
1050 PDEBUG("%p %d %d\n", params
->context
, params
->data_type
,
1051 params
->initial_id
);
1057 * frees smsclient object and all subclients associated with it
1059 * @param client pointer to smsclient object returned by smscore_register_client
1062 void smscore_unregister_client(smscore_client_t
*client
)
1064 smscore_device_t
*coredev
= client
->coredev
;
1065 unsigned long flags
;
1067 spin_lock_irqsave(&coredev
->clientslock
, flags
);
1070 while (!list_empty(&client
->idlist
)) {
1071 smscore_idlist_t
*identry
=
1072 (smscore_idlist_t
*) client
->idlist
.next
;
1073 list_del(&identry
->entry
);
1077 printk(KERN_INFO
"%s %p\n", __func__
, client
->context
);
1079 list_del(&client
->entry
);
1082 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
1086 * verifies that source id is not taken by another client,
1087 * calls device handler to send requests to the device
1089 * @param client pointer to smsclient object returned by smscore_register_client
1090 * @param buffer pointer to a request buffer
1091 * @param size size (in bytes) of request buffer
1093 * @return 0 on success, <0 on error.
1095 int smsclient_sendrequest(smscore_client_t
*client
, void *buffer
, size_t size
)
1097 smscore_device_t
*coredev
;
1098 SmsMsgHdr_ST
*phdr
= (SmsMsgHdr_ST
*) buffer
;
1101 if (client
== NULL
) {
1102 printk(KERN_ERR
"%s Got NULL client\n", __func__
);
1106 coredev
= client
->coredev
;
1108 /* check that no other channel with same id exists */
1109 if (coredev
== NULL
) {
1110 printk(KERN_ERR
"%s Got NULL coredev\n", __func__
);
1114 rc
= smscore_validate_client(client
->coredev
, client
, 0,
1119 return coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
1123 * return the size of large (common) buffer
1125 * @param coredev pointer to a coredev object from clients hotplug
1127 * @return size (in bytes) of the buffer
1129 int smscore_get_common_buffer_size(smscore_device_t
*coredev
)
1131 return coredev
->common_buffer_size
;
1135 * maps common buffer (if supported by platform)
1137 * @param coredev pointer to a coredev object from clients hotplug
1138 * @param vma pointer to vma struct from mmap handler
1140 * @return 0 on success, <0 on error.
1142 int smscore_map_common_buffer(smscore_device_t
*coredev
,
1143 struct vm_area_struct
*vma
)
1145 unsigned long end
= vma
->vm_end
,
1146 start
= vma
->vm_start
,
1147 size
= PAGE_ALIGN(coredev
->common_buffer_size
);
1149 if (!(vma
->vm_flags
& (VM_READ
| VM_SHARED
)) ||
1150 (vma
->vm_flags
& VM_WRITE
)) {
1151 printk(KERN_INFO
"%s invalid vm flags\n", __func__
);
1155 if ((end
- start
) != size
) {
1156 printk(KERN_INFO
"%s invalid size %d expected %d\n",
1157 __func__
, (int)(end
- start
), (int) size
);
1161 if (remap_pfn_range(vma
, start
,
1162 coredev
->common_buffer_phys
>> PAGE_SHIFT
,
1163 size
, pgprot_noncached(vma
->vm_page_prot
)))
1165 printk(KERN_INFO
"%s remap_page_range failed\n", __func__
);
1172 int smscore_module_init(void)
1176 INIT_LIST_HEAD(&g_smscore_notifyees
);
1177 INIT_LIST_HEAD(&g_smscore_devices
);
1178 kmutex_init(&g_smscore_deviceslock
);
1180 INIT_LIST_HEAD(&g_smscore_registry
);
1181 kmutex_init(&g_smscore_registrylock
);
1184 rc
= smsusb_register();
1187 rc
= smsdvb_register();
1189 printk(KERN_INFO
"%s, rc %d\n", __func__
, rc
);
1194 void smscore_module_exit(void)
1197 kmutex_lock(&g_smscore_deviceslock
);
1198 while (!list_empty(&g_smscore_notifyees
)) {
1199 smscore_device_notifyee_t
*notifyee
=
1200 (smscore_device_notifyee_t
*) g_smscore_notifyees
.next
;
1202 list_del(¬ifyee
->entry
);
1205 kmutex_unlock(&g_smscore_deviceslock
);
1207 kmutex_lock(&g_smscore_registrylock
);
1208 while (!list_empty(&g_smscore_registry
)) {
1209 smscore_registry_entry_t
*entry
=
1210 (smscore_registry_entry_t
*) g_smscore_registry
.next
;
1212 list_del(&entry
->entry
);
1215 kmutex_unlock(&g_smscore_registrylock
);
1217 /* DVB UnRegister */
1218 smsdvb_unregister();
1220 /* Unregister USB */
1221 smsusb_unregister();
1223 printk(KERN_INFO
"%s\n", __func__
);
1226 module_init(smscore_module_init
);
1227 module_exit(smscore_module_exit
);
1229 MODULE_DESCRIPTION("smscore");
1230 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1231 MODULE_LICENSE("GPL");