2 * Siano core API module
4 * This file contains implementation for the interface to sms core component
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_dbg
, 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
;
97 void smscore_set_board_id(struct smscore_device_t
*core
, int id
)
102 int smscore_led_state(struct smscore_device_t
*core
, int led
)
105 core
->led_state
= led
;
106 return core
->led_state
;
108 EXPORT_SYMBOL_GPL(smscore_set_board_id
);
110 int smscore_get_board_id(struct smscore_device_t
*core
)
112 return core
->board_id
;
114 EXPORT_SYMBOL_GPL(smscore_get_board_id
);
116 struct smscore_registry_entry_t
{
117 struct list_head entry
;
120 enum sms_device_type_st type
;
123 static struct list_head g_smscore_notifyees
;
124 static struct list_head g_smscore_devices
;
125 static struct mutex g_smscore_deviceslock
;
127 static struct list_head g_smscore_registry
;
128 static struct mutex g_smscore_registrylock
;
130 static int default_mode
= 4;
132 module_param(default_mode
, int, 0644);
133 MODULE_PARM_DESC(default_mode
, "default firmware id (device mode)");
135 static struct smscore_registry_entry_t
*smscore_find_registry(char *devpath
)
137 struct smscore_registry_entry_t
*entry
;
138 struct list_head
*next
;
140 kmutex_lock(&g_smscore_registrylock
);
141 for (next
= g_smscore_registry
.next
;
142 next
!= &g_smscore_registry
;
144 entry
= (struct smscore_registry_entry_t
*) next
;
145 if (!strcmp(entry
->devpath
, devpath
)) {
146 kmutex_unlock(&g_smscore_registrylock
);
150 entry
= (struct smscore_registry_entry_t
*)
151 kmalloc(sizeof(struct smscore_registry_entry_t
),
154 entry
->mode
= default_mode
;
155 strcpy(entry
->devpath
, devpath
);
156 list_add(&entry
->entry
, &g_smscore_registry
);
158 sms_err("failed to create smscore_registry.");
159 kmutex_unlock(&g_smscore_registrylock
);
163 int smscore_registry_getmode(char *devpath
)
165 struct smscore_registry_entry_t
*entry
;
167 entry
= smscore_find_registry(devpath
);
171 sms_err("No registry found.");
175 EXPORT_SYMBOL_GPL(smscore_registry_getmode
);
177 static enum sms_device_type_st
smscore_registry_gettype(char *devpath
)
179 struct smscore_registry_entry_t
*entry
;
181 entry
= smscore_find_registry(devpath
);
185 sms_err("No registry found.");
190 void smscore_registry_setmode(char *devpath
, int mode
)
192 struct smscore_registry_entry_t
*entry
;
194 entry
= smscore_find_registry(devpath
);
198 sms_err("No registry found.");
201 static void smscore_registry_settype(char *devpath
,
202 enum sms_device_type_st type
)
204 struct smscore_registry_entry_t
*entry
;
206 entry
= smscore_find_registry(devpath
);
210 sms_err("No registry found.");
214 static void list_add_locked(struct list_head
*new, struct list_head
*head
,
219 spin_lock_irqsave(lock
, flags
);
223 spin_unlock_irqrestore(lock
, flags
);
227 * register a client callback that called when device plugged in/unplugged
228 * NOTE: if devices exist callback is called immediately for each device
230 * @param hotplug callback
232 * @return 0 on success, <0 on error.
234 int smscore_register_hotplug(hotplug_t hotplug
)
236 struct smscore_device_notifyee_t
*notifyee
;
237 struct list_head
*next
, *first
;
240 kmutex_lock(&g_smscore_deviceslock
);
242 notifyee
= kmalloc(sizeof(struct smscore_device_notifyee_t
),
245 /* now notify callback about existing devices */
246 first
= &g_smscore_devices
;
247 for (next
= first
->next
;
248 next
!= first
&& !rc
;
250 struct smscore_device_t
*coredev
=
251 (struct smscore_device_t
*) next
;
252 rc
= hotplug(coredev
, coredev
->device
, 1);
256 notifyee
->hotplug
= hotplug
;
257 list_add(¬ifyee
->entry
, &g_smscore_notifyees
);
263 kmutex_unlock(&g_smscore_deviceslock
);
267 EXPORT_SYMBOL_GPL(smscore_register_hotplug
);
270 * unregister a client callback that called when device plugged in/unplugged
272 * @param hotplug callback
275 void smscore_unregister_hotplug(hotplug_t hotplug
)
277 struct list_head
*next
, *first
;
279 kmutex_lock(&g_smscore_deviceslock
);
281 first
= &g_smscore_notifyees
;
283 for (next
= first
->next
; next
!= first
;) {
284 struct smscore_device_notifyee_t
*notifyee
=
285 (struct smscore_device_notifyee_t
*) next
;
288 if (notifyee
->hotplug
== hotplug
) {
289 list_del(¬ifyee
->entry
);
294 kmutex_unlock(&g_smscore_deviceslock
);
296 EXPORT_SYMBOL_GPL(smscore_unregister_hotplug
);
298 static void smscore_notify_clients(struct smscore_device_t
*coredev
)
300 struct smscore_client_t
*client
;
302 /* the client must call smscore_unregister_client from remove handler */
303 while (!list_empty(&coredev
->clients
)) {
304 client
= (struct smscore_client_t
*) coredev
->clients
.next
;
305 client
->onremove_handler(client
->context
);
309 static int smscore_notify_callbacks(struct smscore_device_t
*coredev
,
310 struct device
*device
, int arrival
)
312 struct list_head
*next
, *first
;
315 /* note: must be called under g_deviceslock */
317 first
= &g_smscore_notifyees
;
319 for (next
= first
->next
; next
!= first
; next
= next
->next
) {
320 rc
= ((struct smscore_device_notifyee_t
*) next
)->
321 hotplug(coredev
, device
, arrival
);
330 smscore_buffer_t
*smscore_createbuffer(u8
*buffer
, void *common_buffer
,
331 dma_addr_t common_buffer_phys
)
333 struct smscore_buffer_t
*cb
=
334 kmalloc(sizeof(struct smscore_buffer_t
), GFP_KERNEL
);
336 sms_info("kmalloc(...) failed");
341 cb
->offset_in_common
= buffer
- (u8
*) common_buffer
;
342 cb
->phys
= common_buffer_phys
+ cb
->offset_in_common
;
348 * creates coredev object for a device, prepares buffers,
349 * creates buffer mappings, notifies registered hotplugs about new device.
351 * @param params device pointer to struct with device specific parameters
353 * @param coredev pointer to a value that receives created coredev object
355 * @return 0 on success, <0 on error.
357 int smscore_register_device(struct smsdevice_params_t
*params
,
358 struct smscore_device_t
**coredev
)
360 struct smscore_device_t
*dev
;
363 dev
= kzalloc(sizeof(struct smscore_device_t
), GFP_KERNEL
);
365 sms_info("kzalloc(...) failed");
369 /* init list entry so it could be safe in smscore_unregister_device */
370 INIT_LIST_HEAD(&dev
->entry
);
373 INIT_LIST_HEAD(&dev
->clients
);
374 INIT_LIST_HEAD(&dev
->buffers
);
377 spin_lock_init(&dev
->clientslock
);
378 spin_lock_init(&dev
->bufferslock
);
380 /* init completion events */
381 init_completion(&dev
->version_ex_done
);
382 init_completion(&dev
->data_download_done
);
383 init_completion(&dev
->trigger_done
);
384 init_completion(&dev
->init_device_done
);
385 init_completion(&dev
->reload_start_done
);
386 init_completion(&dev
->resume_done
);
388 /* alloc common buffer */
389 dev
->common_buffer_size
= params
->buffer_size
* params
->num_buffers
;
390 dev
->common_buffer
= dma_alloc_coherent(NULL
, dev
->common_buffer_size
,
391 &dev
->common_buffer_phys
,
392 GFP_KERNEL
| GFP_DMA
);
393 if (!dev
->common_buffer
) {
394 smscore_unregister_device(dev
);
398 /* prepare dma buffers */
399 for (buffer
= dev
->common_buffer
;
400 dev
->num_buffers
< params
->num_buffers
;
401 dev
->num_buffers
++, buffer
+= params
->buffer_size
) {
402 struct smscore_buffer_t
*cb
=
403 smscore_createbuffer(buffer
, dev
->common_buffer
,
404 dev
->common_buffer_phys
);
406 smscore_unregister_device(dev
);
410 smscore_putbuffer(dev
, cb
);
413 sms_info("allocated %d buffers", dev
->num_buffers
);
415 dev
->mode
= DEVICE_MODE_NONE
;
416 dev
->context
= params
->context
;
417 dev
->device
= params
->device
;
418 dev
->setmode_handler
= params
->setmode_handler
;
419 dev
->detectmode_handler
= params
->detectmode_handler
;
420 dev
->sendrequest_handler
= params
->sendrequest_handler
;
421 dev
->preload_handler
= params
->preload_handler
;
422 dev
->postload_handler
= params
->postload_handler
;
424 dev
->device_flags
= params
->flags
;
425 strcpy(dev
->devpath
, params
->devpath
);
427 smscore_registry_settype(dev
->devpath
, params
->device_type
);
429 /* add device to devices list */
430 kmutex_lock(&g_smscore_deviceslock
);
431 list_add(&dev
->entry
, &g_smscore_devices
);
432 kmutex_unlock(&g_smscore_deviceslock
);
436 sms_info("device %p created", dev
);
440 EXPORT_SYMBOL_GPL(smscore_register_device
);
443 * sets initial device mode and notifies client hotplugs that device is ready
445 * @param coredev pointer to a coredev object returned by
446 * smscore_register_device
448 * @return 0 on success, <0 on error.
450 int smscore_start_device(struct smscore_device_t
*coredev
)
452 int rc
= smscore_set_device_mode(
453 coredev
, smscore_registry_getmode(coredev
->devpath
));
455 sms_info("set device mode faile , rc %d", rc
);
459 kmutex_lock(&g_smscore_deviceslock
);
461 rc
= smscore_notify_callbacks(coredev
, coredev
->device
, 1);
463 sms_info("device %p started, rc %d", coredev
, rc
);
465 kmutex_unlock(&g_smscore_deviceslock
);
469 EXPORT_SYMBOL_GPL(smscore_start_device
);
471 static int smscore_sendrequest_and_wait(struct smscore_device_t
*coredev
,
472 void *buffer
, size_t size
,
473 struct completion
*completion
)
475 int rc
= coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
477 sms_info("sendrequest returned error %d", rc
);
481 return wait_for_completion_timeout(completion
,
482 msecs_to_jiffies(10000)) ?
486 static int smscore_load_firmware_family2(struct smscore_device_t
*coredev
,
487 void *buffer
, size_t size
)
489 struct SmsFirmware_ST
*firmware
= (struct SmsFirmware_ST
*) buffer
;
490 struct SmsMsgHdr_ST
*msg
;
491 u32 mem_address
= firmware
->StartAddress
;
492 u8
*payload
= firmware
->Payload
;
495 sms_info("loading FW to addr 0x%x size %d",
496 mem_address
, firmware
->Length
);
497 if (coredev
->preload_handler
) {
498 rc
= coredev
->preload_handler(coredev
->context
);
503 /* PAGE_SIZE buffer shall be enough and dma aligned */
504 msg
= kmalloc(PAGE_SIZE
, GFP_KERNEL
| GFP_DMA
);
508 if (coredev
->mode
!= DEVICE_MODE_NONE
) {
509 sms_debug("sending reload command.");
510 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_START_REQ
,
511 sizeof(struct SmsMsgHdr_ST
));
512 rc
= smscore_sendrequest_and_wait(coredev
, msg
,
514 &coredev
->reload_start_done
);
515 mem_address
= *(u32
*) &payload
[20];
518 while (size
&& rc
>= 0) {
519 struct SmsDataDownload_ST
*DataMsg
=
520 (struct SmsDataDownload_ST
*) msg
;
521 int payload_size
= min((int) size
, SMS_MAX_PAYLOAD_SIZE
);
523 SMS_INIT_MSG(msg
, MSG_SMS_DATA_DOWNLOAD_REQ
,
524 (u16
)(sizeof(struct SmsMsgHdr_ST
) +
525 sizeof(u32
) + payload_size
));
527 DataMsg
->MemAddr
= mem_address
;
528 memcpy(DataMsg
->Payload
, payload
, payload_size
);
530 if ((coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) &&
531 (coredev
->mode
== DEVICE_MODE_NONE
))
532 rc
= coredev
->sendrequest_handler(
533 coredev
->context
, DataMsg
,
534 DataMsg
->xMsgHeader
.msgLength
);
536 rc
= smscore_sendrequest_and_wait(
538 DataMsg
->xMsgHeader
.msgLength
,
539 &coredev
->data_download_done
);
541 payload
+= payload_size
;
542 size
-= payload_size
;
543 mem_address
+= payload_size
;
547 if (coredev
->mode
== DEVICE_MODE_NONE
) {
548 struct SmsMsgData_ST
*TriggerMsg
=
549 (struct SmsMsgData_ST
*) msg
;
551 SMS_INIT_MSG(msg
, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ
,
552 sizeof(struct SmsMsgHdr_ST
) +
555 TriggerMsg
->msgData
[0] = firmware
->StartAddress
;
557 TriggerMsg
->msgData
[1] = 5; /* Priority */
558 TriggerMsg
->msgData
[2] = 0x200; /* Stack size */
559 TriggerMsg
->msgData
[3] = 0; /* Parameter */
560 TriggerMsg
->msgData
[4] = 4; /* Task ID */
562 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) {
563 rc
= coredev
->sendrequest_handler(
564 coredev
->context
, TriggerMsg
,
565 TriggerMsg
->xMsgHeader
.msgLength
);
568 rc
= smscore_sendrequest_and_wait(
570 TriggerMsg
->xMsgHeader
.msgLength
,
571 &coredev
->trigger_done
);
573 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_EXEC_REQ
,
574 sizeof(struct SmsMsgHdr_ST
));
576 rc
= coredev
->sendrequest_handler(coredev
->context
,
577 msg
, msg
->msgLength
);
582 sms_debug("rc=%d, postload=%p ", rc
,
583 coredev
->postload_handler
);
587 return ((rc
>= 0) && coredev
->postload_handler
) ?
588 coredev
->postload_handler(coredev
->context
) :
593 * loads specified firmware into a buffer and calls device loadfirmware_handler
595 * @param coredev pointer to a coredev object returned by
596 * smscore_register_device
597 * @param filename null-terminated string specifies firmware file name
598 * @param loadfirmware_handler device handler that loads firmware
600 * @return 0 on success, <0 on error.
602 static int smscore_load_firmware_from_file(struct smscore_device_t
*coredev
,
604 loadfirmware_t loadfirmware_handler
)
607 const struct firmware
*fw
;
610 if (loadfirmware_handler
== NULL
&& !(coredev
->device_flags
&
614 rc
= request_firmware(&fw
, filename
, coredev
->device
);
616 sms_info("failed to open \"%s\"", filename
);
619 sms_info("read FW %s, size=%zd", filename
, fw
->size
);
620 fw_buffer
= kmalloc(ALIGN(fw
->size
, SMS_ALLOC_ALIGNMENT
),
621 GFP_KERNEL
| GFP_DMA
);
623 memcpy(fw_buffer
, fw
->data
, fw
->size
);
625 rc
= (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) ?
626 smscore_load_firmware_family2(coredev
,
629 loadfirmware_handler(coredev
->context
,
630 fw_buffer
, fw
->size
);
634 sms_info("failed to allocate firmware buffer");
638 release_firmware(fw
);
644 * notifies all clients registered with the device, notifies hotplugs,
645 * frees all buffers and coredev object
647 * @param coredev pointer to a coredev object returned by
648 * smscore_register_device
650 * @return 0 on success, <0 on error.
652 void smscore_unregister_device(struct smscore_device_t
*coredev
)
654 struct smscore_buffer_t
*cb
;
658 kmutex_lock(&g_smscore_deviceslock
);
660 smscore_notify_clients(coredev
);
661 smscore_notify_callbacks(coredev
, NULL
, 0);
663 /* at this point all buffers should be back
664 * onresponse must no longer be called */
667 while ((cb
= smscore_getbuffer(coredev
))) {
671 if (num_buffers
== coredev
->num_buffers
)
674 sms_info("exiting although "
675 "not all buffers released.");
679 sms_info("waiting for %d buffer(s)",
680 coredev
->num_buffers
- num_buffers
);
684 sms_info("freed %d buffers", num_buffers
);
686 if (coredev
->common_buffer
)
687 dma_free_coherent(NULL
, coredev
->common_buffer_size
,
688 coredev
->common_buffer
,
689 coredev
->common_buffer_phys
);
691 list_del(&coredev
->entry
);
694 kmutex_unlock(&g_smscore_deviceslock
);
696 sms_info("device %p destroyed", coredev
);
698 EXPORT_SYMBOL_GPL(smscore_unregister_device
);
700 static int smscore_detect_mode(struct smscore_device_t
*coredev
)
702 void *buffer
= kmalloc(sizeof(struct SmsMsgHdr_ST
) + SMS_DMA_ALIGNMENT
,
703 GFP_KERNEL
| GFP_DMA
);
704 struct SmsMsgHdr_ST
*msg
=
705 (struct SmsMsgHdr_ST
*) SMS_ALIGN_ADDRESS(buffer
);
711 SMS_INIT_MSG(msg
, MSG_SMS_GET_VERSION_EX_REQ
,
712 sizeof(struct SmsMsgHdr_ST
));
714 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
,
715 &coredev
->version_ex_done
);
717 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
719 if (wait_for_completion_timeout(&coredev
->resume_done
,
720 msecs_to_jiffies(5000))) {
721 rc
= smscore_sendrequest_and_wait(
722 coredev
, msg
, msg
->msgLength
,
723 &coredev
->version_ex_done
);
725 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
726 "second try, rc %d", rc
);
736 static char *smscore_fw_lkup
[][SMS_NUM_OF_DEVICE_TYPES
] = {
737 /*Stellar NOVA A0 Nova B0 VEGA*/
739 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
741 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
743 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
745 {"none", "none", "none", "none"},
747 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
749 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
751 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
753 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
756 static inline char *sms_get_fw_name(struct smscore_device_t
*coredev
,
757 int mode
, enum sms_device_type_st type
)
759 char **fw
= sms_get_board(smscore_get_board_id(coredev
))->fw
;
760 return (fw
&& fw
[mode
]) ? fw
[mode
] : smscore_fw_lkup
[mode
][type
];
764 * calls device handler to change mode of operation
765 * NOTE: stellar/usb may disconnect when changing mode
767 * @param coredev pointer to a coredev object returned by
768 * smscore_register_device
769 * @param mode requested mode of operation
771 * @return 0 on success, <0 on error.
773 int smscore_set_device_mode(struct smscore_device_t
*coredev
, int mode
)
777 enum sms_device_type_st type
;
779 sms_debug("set device mode to %d", mode
);
780 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) {
781 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_RAW_TUNER
) {
782 sms_err("invalid mode specified %d", mode
);
786 smscore_registry_setmode(coredev
->devpath
, mode
);
788 if (!(coredev
->device_flags
& SMS_DEVICE_NOT_READY
)) {
789 rc
= smscore_detect_mode(coredev
);
791 sms_err("mode detect failed %d", rc
);
796 if (coredev
->mode
== mode
) {
797 sms_info("device mode %d already set", mode
);
801 if (!(coredev
->modes_supported
& (1 << mode
))) {
804 type
= smscore_registry_gettype(coredev
->devpath
);
805 fw_filename
= sms_get_fw_name(coredev
, mode
, type
);
807 rc
= smscore_load_firmware_from_file(coredev
,
810 sms_warn("error %d loading firmware: %s, "
811 "trying again with default firmware",
814 /* try again with the default firmware */
815 fw_filename
= smscore_fw_lkup
[mode
][type
];
816 rc
= smscore_load_firmware_from_file(coredev
,
820 sms_warn("error %d loading "
826 sms_log("firmware download success: %s", fw_filename
);
828 sms_info("mode %d supported by running "
831 buffer
= kmalloc(sizeof(struct SmsMsgData_ST
) +
832 SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
834 struct SmsMsgData_ST
*msg
=
835 (struct SmsMsgData_ST
*)
836 SMS_ALIGN_ADDRESS(buffer
);
838 SMS_INIT_MSG(&msg
->xMsgHeader
, MSG_SMS_INIT_DEVICE_REQ
,
839 sizeof(struct SmsMsgData_ST
));
840 msg
->msgData
[0] = mode
;
842 rc
= smscore_sendrequest_and_wait(
843 coredev
, msg
, msg
->xMsgHeader
.msgLength
,
844 &coredev
->init_device_done
);
848 sms_err("Could not allocate buffer for "
849 "init device message.");
853 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_DVBT_BDA
) {
854 sms_err("invalid mode specified %d", mode
);
858 smscore_registry_setmode(coredev
->devpath
, mode
);
860 if (coredev
->detectmode_handler
)
861 coredev
->detectmode_handler(coredev
->context
,
864 if (coredev
->mode
!= mode
&& coredev
->setmode_handler
)
865 rc
= coredev
->setmode_handler(coredev
->context
, mode
);
869 coredev
->mode
= mode
;
870 coredev
->device_flags
&= ~SMS_DEVICE_NOT_READY
;
874 sms_err("return error code %d.", rc
);
879 * calls device handler to get current mode of operation
881 * @param coredev pointer to a coredev object returned by
882 * smscore_register_device
884 * @return current mode
886 int smscore_get_device_mode(struct smscore_device_t
*coredev
)
888 return coredev
->mode
;
890 EXPORT_SYMBOL_GPL(smscore_get_device_mode
);
893 * find client by response id & type within the clients list.
894 * return client handle or NULL.
896 * @param coredev pointer to a coredev object returned by
897 * smscore_register_device
898 * @param data_type client data type (SMS_DONT_CARE for all types)
899 * @param id client id (SMS_DONT_CARE for all id)
903 smscore_client_t
*smscore_find_client(struct smscore_device_t
*coredev
,
904 int data_type
, int id
)
906 struct smscore_client_t
*client
= NULL
;
907 struct list_head
*next
, *first
;
909 struct list_head
*firstid
, *nextid
;
912 spin_lock_irqsave(&coredev
->clientslock
, flags
);
913 first
= &coredev
->clients
;
914 for (next
= first
->next
;
915 (next
!= first
) && !client
;
917 firstid
= &((struct smscore_client_t
*)next
)->idlist
;
918 for (nextid
= firstid
->next
;
920 nextid
= nextid
->next
) {
921 if ((((struct smscore_idlist_t
*)nextid
)->id
== id
) &&
922 (((struct smscore_idlist_t
*)nextid
)->data_type
== data_type
||
923 (((struct smscore_idlist_t
*)nextid
)->data_type
== 0))) {
924 client
= (struct smscore_client_t
*) next
;
929 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
934 * find client by response id/type, call clients onresponse handler
935 * return buffer to pool on error
937 * @param coredev pointer to a coredev object returned by
938 * smscore_register_device
939 * @param cb pointer to response buffer descriptor
942 void smscore_onresponse(struct smscore_device_t
*coredev
,
943 struct smscore_buffer_t
*cb
)
945 struct SmsMsgHdr_ST
*phdr
=
946 (struct SmsMsgHdr_ST
*)((u8
*) cb
->p
+ cb
->offset
);
947 struct smscore_client_t
*client
=
948 smscore_find_client(coredev
, phdr
->msgType
, phdr
->msgDstId
);
951 static unsigned long last_sample_time
; /* = 0; */
952 static int data_total
; /* = 0; */
953 unsigned long time_now
= jiffies_to_msecs(jiffies
);
955 if (!last_sample_time
)
956 last_sample_time
= time_now
;
958 if (time_now
- last_sample_time
> 10000) {
959 sms_debug("\ndata rate %d bytes/secs",
960 (int)((data_total
* 1000) /
961 (time_now
- last_sample_time
)));
963 last_sample_time
= time_now
;
967 data_total
+= cb
->size
;
968 /* If no client registered for type & id,
969 * check for control client where type is not registered */
971 rc
= client
->onresponse_handler(client
->context
, cb
);
974 switch (phdr
->msgType
) {
975 case MSG_SMS_GET_VERSION_EX_RES
:
977 struct SmsVersionRes_ST
*ver
=
978 (struct SmsVersionRes_ST
*) phdr
;
979 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
980 "id %d prots 0x%x ver %d.%d",
981 ver
->FirmwareId
, ver
->SupportedProtocols
,
982 ver
->RomVersionMajor
, ver
->RomVersionMinor
);
984 coredev
->mode
= ver
->FirmwareId
== 255 ?
985 DEVICE_MODE_NONE
: ver
->FirmwareId
;
986 coredev
->modes_supported
= ver
->SupportedProtocols
;
988 complete(&coredev
->version_ex_done
);
991 case MSG_SMS_INIT_DEVICE_RES
:
992 sms_debug("MSG_SMS_INIT_DEVICE_RES");
993 complete(&coredev
->init_device_done
);
995 case MSG_SW_RELOAD_START_RES
:
996 sms_debug("MSG_SW_RELOAD_START_RES");
997 complete(&coredev
->reload_start_done
);
999 case MSG_SMS_DATA_DOWNLOAD_RES
:
1000 complete(&coredev
->data_download_done
);
1002 case MSG_SW_RELOAD_EXEC_RES
:
1003 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1005 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES
:
1006 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1007 complete(&coredev
->trigger_done
);
1009 case MSG_SMS_SLEEP_RESUME_COMP_IND
:
1010 complete(&coredev
->resume_done
);
1015 smscore_putbuffer(coredev
, cb
);
1018 EXPORT_SYMBOL_GPL(smscore_onresponse
);
1021 * return pointer to next free buffer descriptor from core pool
1023 * @param coredev pointer to a coredev object returned by
1024 * smscore_register_device
1026 * @return pointer to descriptor on success, NULL on error.
1028 struct smscore_buffer_t
*smscore_getbuffer(struct smscore_device_t
*coredev
)
1030 struct smscore_buffer_t
*cb
= NULL
;
1031 unsigned long flags
;
1033 spin_lock_irqsave(&coredev
->bufferslock
, flags
);
1035 if (!list_empty(&coredev
->buffers
)) {
1036 cb
= (struct smscore_buffer_t
*) coredev
->buffers
.next
;
1037 list_del(&cb
->entry
);
1040 spin_unlock_irqrestore(&coredev
->bufferslock
, flags
);
1044 EXPORT_SYMBOL_GPL(smscore_getbuffer
);
1047 * return buffer descriptor to a pool
1049 * @param coredev pointer to a coredev object returned by
1050 * smscore_register_device
1051 * @param cb pointer buffer descriptor
1054 void smscore_putbuffer(struct smscore_device_t
*coredev
,
1055 struct smscore_buffer_t
*cb
)
1057 list_add_locked(&cb
->entry
, &coredev
->buffers
, &coredev
->bufferslock
);
1059 EXPORT_SYMBOL_GPL(smscore_putbuffer
);
1061 static int smscore_validate_client(struct smscore_device_t
*coredev
,
1062 struct smscore_client_t
*client
,
1063 int data_type
, int id
)
1065 struct smscore_idlist_t
*listentry
;
1066 struct smscore_client_t
*registered_client
;
1069 sms_err("bad parameter.");
1072 registered_client
= smscore_find_client(coredev
, data_type
, id
);
1073 if (registered_client
== client
)
1076 if (registered_client
) {
1077 sms_err("The msg ID already registered to another client.");
1080 listentry
= kzalloc(sizeof(struct smscore_idlist_t
), GFP_KERNEL
);
1082 sms_err("Can't allocate memory for client id.");
1086 listentry
->data_type
= data_type
;
1087 list_add_locked(&listentry
->entry
, &client
->idlist
,
1088 &coredev
->clientslock
);
1093 * creates smsclient object, check that id is taken by another client
1095 * @param coredev pointer to a coredev object from clients hotplug
1096 * @param initial_id all messages with this id would be sent to this client
1097 * @param data_type all messages of this type would be sent to this client
1098 * @param onresponse_handler client handler that is called to
1099 * process incoming messages
1100 * @param onremove_handler client handler that is called when device is removed
1101 * @param context client-specific context
1102 * @param client pointer to a value that receives created smsclient object
1104 * @return 0 on success, <0 on error.
1106 int smscore_register_client(struct smscore_device_t
*coredev
,
1107 struct smsclient_params_t
*params
,
1108 struct smscore_client_t
**client
)
1110 struct smscore_client_t
*newclient
;
1111 /* check that no other channel with same parameters exists */
1112 if (smscore_find_client(coredev
, params
->data_type
,
1113 params
->initial_id
)) {
1114 sms_err("Client already exist.");
1118 newclient
= kzalloc(sizeof(struct smscore_client_t
), GFP_KERNEL
);
1120 sms_err("Failed to allocate memory for client.");
1124 INIT_LIST_HEAD(&newclient
->idlist
);
1125 newclient
->coredev
= coredev
;
1126 newclient
->onresponse_handler
= params
->onresponse_handler
;
1127 newclient
->onremove_handler
= params
->onremove_handler
;
1128 newclient
->context
= params
->context
;
1129 list_add_locked(&newclient
->entry
, &coredev
->clients
,
1130 &coredev
->clientslock
);
1131 smscore_validate_client(coredev
, newclient
, params
->data_type
,
1132 params
->initial_id
);
1133 *client
= newclient
;
1134 sms_debug("%p %d %d", params
->context
, params
->data_type
,
1135 params
->initial_id
);
1139 EXPORT_SYMBOL_GPL(smscore_register_client
);
1142 * frees smsclient object and all subclients associated with it
1144 * @param client pointer to smsclient object returned by
1145 * smscore_register_client
1148 void smscore_unregister_client(struct smscore_client_t
*client
)
1150 struct smscore_device_t
*coredev
= client
->coredev
;
1151 unsigned long flags
;
1153 spin_lock_irqsave(&coredev
->clientslock
, flags
);
1156 while (!list_empty(&client
->idlist
)) {
1157 struct smscore_idlist_t
*identry
=
1158 (struct smscore_idlist_t
*) client
->idlist
.next
;
1159 list_del(&identry
->entry
);
1163 sms_info("%p", client
->context
);
1165 list_del(&client
->entry
);
1168 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
1170 EXPORT_SYMBOL_GPL(smscore_unregister_client
);
1173 * verifies that source id is not taken by another client,
1174 * calls device handler to send requests to the device
1176 * @param client pointer to smsclient object returned by
1177 * smscore_register_client
1178 * @param buffer pointer to a request buffer
1179 * @param size size (in bytes) of request buffer
1181 * @return 0 on success, <0 on error.
1183 int smsclient_sendrequest(struct smscore_client_t
*client
,
1184 void *buffer
, size_t size
)
1186 struct smscore_device_t
*coredev
;
1187 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) buffer
;
1190 if (client
== NULL
) {
1191 sms_err("Got NULL client");
1195 coredev
= client
->coredev
;
1197 /* check that no other channel with same id exists */
1198 if (coredev
== NULL
) {
1199 sms_err("Got NULL coredev");
1203 rc
= smscore_validate_client(client
->coredev
, client
, 0,
1208 return coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
1210 EXPORT_SYMBOL_GPL(smsclient_sendrequest
);
1213 int smscore_configure_gpio(struct smscore_device_t
*coredev
, u32 pin
,
1214 struct smscore_gpio_config
*pinconfig
)
1217 struct SmsMsgHdr_ST hdr
;
1221 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) {
1222 msg
.hdr
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1223 msg
.hdr
.msgDstId
= HIF_TASK
;
1224 msg
.hdr
.msgFlags
= 0;
1225 msg
.hdr
.msgType
= MSG_SMS_GPIO_CONFIG_EX_REQ
;
1226 msg
.hdr
.msgLength
= sizeof(msg
);
1229 msg
.data
[1] = pinconfig
->pullupdown
;
1231 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1232 msg
.data
[2] = pinconfig
->outputslewrate
== 0 ? 3 : 0;
1234 switch (pinconfig
->outputdriving
) {
1235 case SMS_GPIO_OUTPUTDRIVING_16mA
:
1236 msg
.data
[3] = 7; /* Nova - 16mA */
1238 case SMS_GPIO_OUTPUTDRIVING_12mA
:
1239 msg
.data
[3] = 5; /* Nova - 11mA */
1241 case SMS_GPIO_OUTPUTDRIVING_8mA
:
1242 msg
.data
[3] = 3; /* Nova - 7mA */
1244 case SMS_GPIO_OUTPUTDRIVING_4mA
:
1246 msg
.data
[3] = 2; /* Nova - 4mA */
1250 msg
.data
[4] = pinconfig
->direction
;
1252 } else /* TODO: SMS_DEVICE_FAMILY1 */
1255 return coredev
->sendrequest_handler(coredev
->context
,
1259 int smscore_set_gpio(struct smscore_device_t
*coredev
, u32 pin
, int level
)
1262 struct SmsMsgHdr_ST hdr
;
1266 if (pin
> MAX_GPIO_PIN_NUMBER
)
1269 msg
.hdr
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1270 msg
.hdr
.msgDstId
= HIF_TASK
;
1271 msg
.hdr
.msgFlags
= 0;
1272 msg
.hdr
.msgType
= MSG_SMS_GPIO_SET_LEVEL_REQ
;
1273 msg
.hdr
.msgLength
= sizeof(msg
);
1276 msg
.data
[1] = level
? 1 : 0;
1279 return coredev
->sendrequest_handler(coredev
->context
,
1283 static int __init
smscore_module_init(void)
1287 INIT_LIST_HEAD(&g_smscore_notifyees
);
1288 INIT_LIST_HEAD(&g_smscore_devices
);
1289 kmutex_init(&g_smscore_deviceslock
);
1291 INIT_LIST_HEAD(&g_smscore_registry
);
1292 kmutex_init(&g_smscore_registrylock
);
1300 sms_debug("rc %d", rc
);
1305 static void __exit
smscore_module_exit(void)
1312 kmutex_lock(&g_smscore_deviceslock
);
1313 while (!list_empty(&g_smscore_notifyees
)) {
1314 struct smscore_device_notifyee_t
*notifyee
=
1315 (struct smscore_device_notifyee_t
*)
1316 g_smscore_notifyees
.next
;
1318 list_del(¬ifyee
->entry
);
1321 kmutex_unlock(&g_smscore_deviceslock
);
1323 kmutex_lock(&g_smscore_registrylock
);
1324 while (!list_empty(&g_smscore_registry
)) {
1325 struct smscore_registry_entry_t
*entry
=
1326 (struct smscore_registry_entry_t
*)
1327 g_smscore_registry
.next
;
1329 list_del(&entry
->entry
);
1332 kmutex_unlock(&g_smscore_registrylock
);
1337 module_init(smscore_module_init
);
1338 module_exit(smscore_module_exit
);
1340 MODULE_DESCRIPTION("Siano MDTV Core module");
1341 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1342 MODULE_LICENSE("GPL");