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>
31 #include <linux/slab.h>
33 #include <linux/firmware.h>
34 #include <linux/wait.h>
35 #include <asm/byteorder.h>
37 #include "smscoreapi.h"
38 #include "sms-cards.h"
40 #include "smsendian.h"
43 module_param_named(debug
, sms_dbg
, int, 0644);
44 MODULE_PARM_DESC(debug
, "set debug level (info=1, adv=2 (or-able))");
46 struct smscore_device_notifyee_t
{
47 struct list_head entry
;
51 struct smscore_idlist_t
{
52 struct list_head entry
;
57 struct smscore_client_t
{
58 struct list_head entry
;
59 struct smscore_device_t
*coredev
;
61 struct list_head idlist
;
62 onresponse_t onresponse_handler
;
63 onremove_t onremove_handler
;
66 void smscore_set_board_id(struct smscore_device_t
*core
, int id
)
71 int smscore_led_state(struct smscore_device_t
*core
, int led
)
74 core
->led_state
= led
;
75 return core
->led_state
;
77 EXPORT_SYMBOL_GPL(smscore_set_board_id
);
79 int smscore_get_board_id(struct smscore_device_t
*core
)
81 return core
->board_id
;
83 EXPORT_SYMBOL_GPL(smscore_get_board_id
);
85 struct smscore_registry_entry_t
{
86 struct list_head entry
;
89 enum sms_device_type_st type
;
92 static struct list_head g_smscore_notifyees
;
93 static struct list_head g_smscore_devices
;
94 static struct mutex g_smscore_deviceslock
;
96 static struct list_head g_smscore_registry
;
97 static struct mutex g_smscore_registrylock
;
99 static int default_mode
= 4;
101 module_param(default_mode
, int, 0644);
102 MODULE_PARM_DESC(default_mode
, "default firmware id (device mode)");
104 static struct smscore_registry_entry_t
*smscore_find_registry(char *devpath
)
106 struct smscore_registry_entry_t
*entry
;
107 struct list_head
*next
;
109 kmutex_lock(&g_smscore_registrylock
);
110 for (next
= g_smscore_registry
.next
;
111 next
!= &g_smscore_registry
;
113 entry
= (struct smscore_registry_entry_t
*) next
;
114 if (!strcmp(entry
->devpath
, devpath
)) {
115 kmutex_unlock(&g_smscore_registrylock
);
119 entry
= kmalloc(sizeof(struct smscore_registry_entry_t
), GFP_KERNEL
);
121 entry
->mode
= default_mode
;
122 strcpy(entry
->devpath
, devpath
);
123 list_add(&entry
->entry
, &g_smscore_registry
);
125 sms_err("failed to create smscore_registry.");
126 kmutex_unlock(&g_smscore_registrylock
);
130 int smscore_registry_getmode(char *devpath
)
132 struct smscore_registry_entry_t
*entry
;
134 entry
= smscore_find_registry(devpath
);
138 sms_err("No registry found.");
142 EXPORT_SYMBOL_GPL(smscore_registry_getmode
);
144 static enum sms_device_type_st
smscore_registry_gettype(char *devpath
)
146 struct smscore_registry_entry_t
*entry
;
148 entry
= smscore_find_registry(devpath
);
152 sms_err("No registry found.");
157 void smscore_registry_setmode(char *devpath
, int mode
)
159 struct smscore_registry_entry_t
*entry
;
161 entry
= smscore_find_registry(devpath
);
165 sms_err("No registry found.");
168 static void smscore_registry_settype(char *devpath
,
169 enum sms_device_type_st type
)
171 struct smscore_registry_entry_t
*entry
;
173 entry
= smscore_find_registry(devpath
);
177 sms_err("No registry found.");
181 static void list_add_locked(struct list_head
*new, struct list_head
*head
,
186 spin_lock_irqsave(lock
, flags
);
190 spin_unlock_irqrestore(lock
, flags
);
194 * register a client callback that called when device plugged in/unplugged
195 * NOTE: if devices exist callback is called immediately for each device
197 * @param hotplug callback
199 * @return 0 on success, <0 on error.
201 int smscore_register_hotplug(hotplug_t hotplug
)
203 struct smscore_device_notifyee_t
*notifyee
;
204 struct list_head
*next
, *first
;
207 kmutex_lock(&g_smscore_deviceslock
);
209 notifyee
= kmalloc(sizeof(struct smscore_device_notifyee_t
),
212 /* now notify callback about existing devices */
213 first
= &g_smscore_devices
;
214 for (next
= first
->next
;
215 next
!= first
&& !rc
;
217 struct smscore_device_t
*coredev
=
218 (struct smscore_device_t
*) next
;
219 rc
= hotplug(coredev
, coredev
->device
, 1);
223 notifyee
->hotplug
= hotplug
;
224 list_add(¬ifyee
->entry
, &g_smscore_notifyees
);
230 kmutex_unlock(&g_smscore_deviceslock
);
234 EXPORT_SYMBOL_GPL(smscore_register_hotplug
);
237 * unregister a client callback that called when device plugged in/unplugged
239 * @param hotplug callback
242 void smscore_unregister_hotplug(hotplug_t hotplug
)
244 struct list_head
*next
, *first
;
246 kmutex_lock(&g_smscore_deviceslock
);
248 first
= &g_smscore_notifyees
;
250 for (next
= first
->next
; next
!= first
;) {
251 struct smscore_device_notifyee_t
*notifyee
=
252 (struct smscore_device_notifyee_t
*) next
;
255 if (notifyee
->hotplug
== hotplug
) {
256 list_del(¬ifyee
->entry
);
261 kmutex_unlock(&g_smscore_deviceslock
);
263 EXPORT_SYMBOL_GPL(smscore_unregister_hotplug
);
265 static void smscore_notify_clients(struct smscore_device_t
*coredev
)
267 struct smscore_client_t
*client
;
269 /* the client must call smscore_unregister_client from remove handler */
270 while (!list_empty(&coredev
->clients
)) {
271 client
= (struct smscore_client_t
*) coredev
->clients
.next
;
272 client
->onremove_handler(client
->context
);
276 static int smscore_notify_callbacks(struct smscore_device_t
*coredev
,
277 struct device
*device
, int arrival
)
279 struct smscore_device_notifyee_t
*elem
;
282 /* note: must be called under g_deviceslock */
284 list_for_each_entry(elem
, &g_smscore_notifyees
, entry
) {
285 rc
= elem
->hotplug(coredev
, device
, arrival
);
294 smscore_buffer_t
*smscore_createbuffer(u8
*buffer
, void *common_buffer
,
295 dma_addr_t common_buffer_phys
)
297 struct smscore_buffer_t
*cb
=
298 kmalloc(sizeof(struct smscore_buffer_t
), GFP_KERNEL
);
300 sms_info("kmalloc(...) failed");
305 cb
->offset_in_common
= buffer
- (u8
*) common_buffer
;
306 cb
->phys
= common_buffer_phys
+ cb
->offset_in_common
;
312 * creates coredev object for a device, prepares buffers,
313 * creates buffer mappings, notifies registered hotplugs about new device.
315 * @param params device pointer to struct with device specific parameters
317 * @param coredev pointer to a value that receives created coredev object
319 * @return 0 on success, <0 on error.
321 int smscore_register_device(struct smsdevice_params_t
*params
,
322 struct smscore_device_t
**coredev
)
324 struct smscore_device_t
*dev
;
327 dev
= kzalloc(sizeof(struct smscore_device_t
), GFP_KERNEL
);
329 sms_info("kzalloc(...) failed");
333 /* init list entry so it could be safe in smscore_unregister_device */
334 INIT_LIST_HEAD(&dev
->entry
);
337 INIT_LIST_HEAD(&dev
->clients
);
338 INIT_LIST_HEAD(&dev
->buffers
);
341 spin_lock_init(&dev
->clientslock
);
342 spin_lock_init(&dev
->bufferslock
);
344 /* init completion events */
345 init_completion(&dev
->version_ex_done
);
346 init_completion(&dev
->data_download_done
);
347 init_completion(&dev
->trigger_done
);
348 init_completion(&dev
->init_device_done
);
349 init_completion(&dev
->reload_start_done
);
350 init_completion(&dev
->resume_done
);
351 init_completion(&dev
->gpio_configuration_done
);
352 init_completion(&dev
->gpio_set_level_done
);
353 init_completion(&dev
->gpio_get_level_done
);
354 init_completion(&dev
->ir_init_done
);
356 /* Buffer management */
357 init_waitqueue_head(&dev
->buffer_mng_waitq
);
359 /* alloc common buffer */
360 dev
->common_buffer_size
= params
->buffer_size
* params
->num_buffers
;
361 dev
->common_buffer
= dma_alloc_coherent(NULL
, dev
->common_buffer_size
,
362 &dev
->common_buffer_phys
,
363 GFP_KERNEL
| GFP_DMA
);
364 if (!dev
->common_buffer
) {
365 smscore_unregister_device(dev
);
369 /* prepare dma buffers */
370 for (buffer
= dev
->common_buffer
;
371 dev
->num_buffers
< params
->num_buffers
;
372 dev
->num_buffers
++, buffer
+= params
->buffer_size
) {
373 struct smscore_buffer_t
*cb
=
374 smscore_createbuffer(buffer
, dev
->common_buffer
,
375 dev
->common_buffer_phys
);
377 smscore_unregister_device(dev
);
381 smscore_putbuffer(dev
, cb
);
384 sms_info("allocated %d buffers", dev
->num_buffers
);
386 dev
->mode
= DEVICE_MODE_NONE
;
387 dev
->context
= params
->context
;
388 dev
->device
= params
->device
;
389 dev
->setmode_handler
= params
->setmode_handler
;
390 dev
->detectmode_handler
= params
->detectmode_handler
;
391 dev
->sendrequest_handler
= params
->sendrequest_handler
;
392 dev
->preload_handler
= params
->preload_handler
;
393 dev
->postload_handler
= params
->postload_handler
;
395 dev
->device_flags
= params
->flags
;
396 strcpy(dev
->devpath
, params
->devpath
);
398 smscore_registry_settype(dev
->devpath
, params
->device_type
);
400 /* add device to devices list */
401 kmutex_lock(&g_smscore_deviceslock
);
402 list_add(&dev
->entry
, &g_smscore_devices
);
403 kmutex_unlock(&g_smscore_deviceslock
);
407 sms_info("device %p created", dev
);
411 EXPORT_SYMBOL_GPL(smscore_register_device
);
414 static int smscore_sendrequest_and_wait(struct smscore_device_t
*coredev
,
415 void *buffer
, size_t size
, struct completion
*completion
) {
416 int rc
= coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
418 sms_info("sendrequest returned error %d", rc
);
422 return wait_for_completion_timeout(completion
,
423 msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS
)) ?
428 * Starts & enables IR operations
430 * @return 0 on success, < 0 on error.
432 static int smscore_init_ir(struct smscore_device_t
*coredev
)
438 coredev
->ir
.dev
= NULL
;
439 ir_io
= sms_get_board(smscore_get_board_id(coredev
))->board_cfg
.ir
;
440 if (ir_io
) {/* only if IR port exist we use IR sub-module */
441 sms_info("IR loading");
442 rc
= sms_ir_init(coredev
);
445 sms_err("Error initialization DTV IR sub-module");
447 buffer
= kmalloc(sizeof(struct SmsMsgData_ST2
) +
449 GFP_KERNEL
| GFP_DMA
);
451 struct SmsMsgData_ST2
*msg
=
452 (struct SmsMsgData_ST2
*)
453 SMS_ALIGN_ADDRESS(buffer
);
455 SMS_INIT_MSG(&msg
->xMsgHeader
,
456 MSG_SMS_START_IR_REQ
,
457 sizeof(struct SmsMsgData_ST2
));
458 msg
->msgData
[0] = coredev
->ir
.controller
;
459 msg
->msgData
[1] = coredev
->ir
.timeout
;
461 smsendian_handle_tx_message(
462 (struct SmsMsgHdr_ST2
*)msg
);
463 rc
= smscore_sendrequest_and_wait(coredev
, msg
,
464 msg
->xMsgHeader
. msgLength
,
465 &coredev
->ir_init_done
);
470 ("Sending IR initialization message failed");
473 sms_info("IR port has not been detected");
479 * sets initial device mode and notifies client hotplugs that device is ready
481 * @param coredev pointer to a coredev object returned by
482 * smscore_register_device
484 * @return 0 on success, <0 on error.
486 int smscore_start_device(struct smscore_device_t
*coredev
)
488 int rc
= smscore_set_device_mode(
489 coredev
, smscore_registry_getmode(coredev
->devpath
));
491 sms_info("set device mode faile , rc %d", rc
);
495 kmutex_lock(&g_smscore_deviceslock
);
497 rc
= smscore_notify_callbacks(coredev
, coredev
->device
, 1);
498 smscore_init_ir(coredev
);
500 sms_info("device %p started, rc %d", coredev
, rc
);
502 kmutex_unlock(&g_smscore_deviceslock
);
506 EXPORT_SYMBOL_GPL(smscore_start_device
);
509 static int smscore_load_firmware_family2(struct smscore_device_t
*coredev
,
510 void *buffer
, size_t size
)
512 struct SmsFirmware_ST
*firmware
= (struct SmsFirmware_ST
*) buffer
;
513 struct SmsMsgHdr_ST
*msg
;
515 u8
*payload
= firmware
->Payload
;
517 firmware
->StartAddress
= le32_to_cpu(firmware
->StartAddress
);
518 firmware
->Length
= le32_to_cpu(firmware
->Length
);
520 mem_address
= firmware
->StartAddress
;
522 sms_info("loading FW to addr 0x%x size %d",
523 mem_address
, firmware
->Length
);
524 if (coredev
->preload_handler
) {
525 rc
= coredev
->preload_handler(coredev
->context
);
530 /* PAGE_SIZE buffer shall be enough and dma aligned */
531 msg
= kmalloc(PAGE_SIZE
, GFP_KERNEL
| GFP_DMA
);
535 if (coredev
->mode
!= DEVICE_MODE_NONE
) {
536 sms_debug("sending reload command.");
537 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_START_REQ
,
538 sizeof(struct SmsMsgHdr_ST
));
539 rc
= smscore_sendrequest_and_wait(coredev
, msg
,
541 &coredev
->reload_start_done
);
542 mem_address
= *(u32
*) &payload
[20];
545 while (size
&& rc
>= 0) {
546 struct SmsDataDownload_ST
*DataMsg
=
547 (struct SmsDataDownload_ST
*) msg
;
548 int payload_size
= min((int) size
, SMS_MAX_PAYLOAD_SIZE
);
550 SMS_INIT_MSG(msg
, MSG_SMS_DATA_DOWNLOAD_REQ
,
551 (u16
)(sizeof(struct SmsMsgHdr_ST
) +
552 sizeof(u32
) + payload_size
));
554 DataMsg
->MemAddr
= mem_address
;
555 memcpy(DataMsg
->Payload
, payload
, payload_size
);
557 if ((coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) &&
558 (coredev
->mode
== DEVICE_MODE_NONE
))
559 rc
= coredev
->sendrequest_handler(
560 coredev
->context
, DataMsg
,
561 DataMsg
->xMsgHeader
.msgLength
);
563 rc
= smscore_sendrequest_and_wait(
565 DataMsg
->xMsgHeader
.msgLength
,
566 &coredev
->data_download_done
);
568 payload
+= payload_size
;
569 size
-= payload_size
;
570 mem_address
+= payload_size
;
574 if (coredev
->mode
== DEVICE_MODE_NONE
) {
575 struct SmsMsgData_ST
*TriggerMsg
=
576 (struct SmsMsgData_ST
*) msg
;
578 SMS_INIT_MSG(msg
, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ
,
579 sizeof(struct SmsMsgHdr_ST
) +
582 TriggerMsg
->msgData
[0] = firmware
->StartAddress
;
584 TriggerMsg
->msgData
[1] = 5; /* Priority */
585 TriggerMsg
->msgData
[2] = 0x200; /* Stack size */
586 TriggerMsg
->msgData
[3] = 0; /* Parameter */
587 TriggerMsg
->msgData
[4] = 4; /* Task ID */
589 if (coredev
->device_flags
& SMS_ROM_NO_RESPONSE
) {
590 rc
= coredev
->sendrequest_handler(
591 coredev
->context
, TriggerMsg
,
592 TriggerMsg
->xMsgHeader
.msgLength
);
595 rc
= smscore_sendrequest_and_wait(
597 TriggerMsg
->xMsgHeader
.msgLength
,
598 &coredev
->trigger_done
);
600 SMS_INIT_MSG(msg
, MSG_SW_RELOAD_EXEC_REQ
,
601 sizeof(struct SmsMsgHdr_ST
));
603 rc
= coredev
->sendrequest_handler(coredev
->context
,
604 msg
, msg
->msgLength
);
609 sms_debug("rc=%d, postload=%p ", rc
,
610 coredev
->postload_handler
);
614 return ((rc
>= 0) && coredev
->postload_handler
) ?
615 coredev
->postload_handler(coredev
->context
) :
620 * loads specified firmware into a buffer and calls device loadfirmware_handler
622 * @param coredev pointer to a coredev object returned by
623 * smscore_register_device
624 * @param filename null-terminated string specifies firmware file name
625 * @param loadfirmware_handler device handler that loads firmware
627 * @return 0 on success, <0 on error.
629 static int smscore_load_firmware_from_file(struct smscore_device_t
*coredev
,
631 loadfirmware_t loadfirmware_handler
)
634 const struct firmware
*fw
;
637 if (loadfirmware_handler
== NULL
&& !(coredev
->device_flags
&
641 rc
= request_firmware(&fw
, filename
, coredev
->device
);
643 sms_info("failed to open \"%s\"", filename
);
646 sms_info("read FW %s, size=%zd", filename
, fw
->size
);
647 fw_buffer
= kmalloc(ALIGN(fw
->size
, SMS_ALLOC_ALIGNMENT
),
648 GFP_KERNEL
| GFP_DMA
);
650 memcpy(fw_buffer
, fw
->data
, fw
->size
);
652 rc
= (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) ?
653 smscore_load_firmware_family2(coredev
,
656 loadfirmware_handler(coredev
->context
,
657 fw_buffer
, fw
->size
);
661 sms_info("failed to allocate firmware buffer");
665 release_firmware(fw
);
671 * notifies all clients registered with the device, notifies hotplugs,
672 * frees all buffers and coredev object
674 * @param coredev pointer to a coredev object returned by
675 * smscore_register_device
677 * @return 0 on success, <0 on error.
679 void smscore_unregister_device(struct smscore_device_t
*coredev
)
681 struct smscore_buffer_t
*cb
;
685 kmutex_lock(&g_smscore_deviceslock
);
687 /* Release input device (IR) resources */
688 sms_ir_exit(coredev
);
690 smscore_notify_clients(coredev
);
691 smscore_notify_callbacks(coredev
, NULL
, 0);
693 /* at this point all buffers should be back
694 * onresponse must no longer be called */
697 while (!list_empty(&coredev
->buffers
)) {
698 cb
= (struct smscore_buffer_t
*) coredev
->buffers
.next
;
699 list_del(&cb
->entry
);
703 if (num_buffers
== coredev
->num_buffers
)
706 sms_info("exiting although "
707 "not all buffers released.");
711 sms_info("waiting for %d buffer(s)",
712 coredev
->num_buffers
- num_buffers
);
716 sms_info("freed %d buffers", num_buffers
);
718 if (coredev
->common_buffer
)
719 dma_free_coherent(NULL
, coredev
->common_buffer_size
,
720 coredev
->common_buffer
, coredev
->common_buffer_phys
);
722 if (coredev
->fw_buf
!= NULL
)
723 kfree(coredev
->fw_buf
);
725 list_del(&coredev
->entry
);
728 kmutex_unlock(&g_smscore_deviceslock
);
730 sms_info("device %p destroyed", coredev
);
732 EXPORT_SYMBOL_GPL(smscore_unregister_device
);
734 static int smscore_detect_mode(struct smscore_device_t
*coredev
)
736 void *buffer
= kmalloc(sizeof(struct SmsMsgHdr_ST
) + SMS_DMA_ALIGNMENT
,
737 GFP_KERNEL
| GFP_DMA
);
738 struct SmsMsgHdr_ST
*msg
=
739 (struct SmsMsgHdr_ST
*) SMS_ALIGN_ADDRESS(buffer
);
745 SMS_INIT_MSG(msg
, MSG_SMS_GET_VERSION_EX_REQ
,
746 sizeof(struct SmsMsgHdr_ST
));
748 rc
= smscore_sendrequest_and_wait(coredev
, msg
, msg
->msgLength
,
749 &coredev
->version_ex_done
);
751 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
753 if (wait_for_completion_timeout(&coredev
->resume_done
,
754 msecs_to_jiffies(5000))) {
755 rc
= smscore_sendrequest_and_wait(
756 coredev
, msg
, msg
->msgLength
,
757 &coredev
->version_ex_done
);
759 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
760 "second try, rc %d", rc
);
770 static char *smscore_fw_lkup
[][SMS_NUM_OF_DEVICE_TYPES
] = {
771 /*Stellar NOVA A0 Nova B0 VEGA*/
773 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
775 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
777 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
779 {"none", "none", "none", "none"},
781 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
783 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
785 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
787 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
790 static inline char *sms_get_fw_name(struct smscore_device_t
*coredev
,
791 int mode
, enum sms_device_type_st type
)
793 char **fw
= sms_get_board(smscore_get_board_id(coredev
))->fw
;
794 return (fw
&& fw
[mode
]) ? fw
[mode
] : smscore_fw_lkup
[mode
][type
];
798 * calls device handler to change mode of operation
799 * NOTE: stellar/usb may disconnect when changing mode
801 * @param coredev pointer to a coredev object returned by
802 * smscore_register_device
803 * @param mode requested mode of operation
805 * @return 0 on success, <0 on error.
807 int smscore_set_device_mode(struct smscore_device_t
*coredev
, int mode
)
811 enum sms_device_type_st type
;
813 sms_debug("set device mode to %d", mode
);
814 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) {
815 if (mode
< DEVICE_MODE_DVBT
|| mode
>= DEVICE_MODE_RAW_TUNER
) {
816 sms_err("invalid mode specified %d", mode
);
820 smscore_registry_setmode(coredev
->devpath
, mode
);
822 if (!(coredev
->device_flags
& SMS_DEVICE_NOT_READY
)) {
823 rc
= smscore_detect_mode(coredev
);
825 sms_err("mode detect failed %d", rc
);
830 if (coredev
->mode
== mode
) {
831 sms_info("device mode %d already set", mode
);
835 if (!(coredev
->modes_supported
& (1 << mode
))) {
838 type
= smscore_registry_gettype(coredev
->devpath
);
839 fw_filename
= sms_get_fw_name(coredev
, mode
, type
);
841 rc
= smscore_load_firmware_from_file(coredev
,
844 sms_warn("error %d loading firmware: %s, "
845 "trying again with default firmware",
848 /* try again with the default firmware */
849 fw_filename
= smscore_fw_lkup
[mode
][type
];
850 rc
= smscore_load_firmware_from_file(coredev
,
854 sms_warn("error %d loading "
860 sms_log("firmware download success: %s", fw_filename
);
862 sms_info("mode %d supported by running "
865 buffer
= kmalloc(sizeof(struct SmsMsgData_ST
) +
866 SMS_DMA_ALIGNMENT
, GFP_KERNEL
| GFP_DMA
);
868 struct SmsMsgData_ST
*msg
=
869 (struct SmsMsgData_ST
*)
870 SMS_ALIGN_ADDRESS(buffer
);
872 SMS_INIT_MSG(&msg
->xMsgHeader
, MSG_SMS_INIT_DEVICE_REQ
,
873 sizeof(struct SmsMsgData_ST
));
874 msg
->msgData
[0] = mode
;
876 rc
= smscore_sendrequest_and_wait(
877 coredev
, msg
, msg
->xMsgHeader
.msgLength
,
878 &coredev
->init_device_done
);
882 sms_err("Could not allocate buffer for "
883 "init device message.");
887 if (mode
< DEVICE_MODE_DVBT
|| mode
> DEVICE_MODE_DVBT_BDA
) {
888 sms_err("invalid mode specified %d", mode
);
892 smscore_registry_setmode(coredev
->devpath
, mode
);
894 if (coredev
->detectmode_handler
)
895 coredev
->detectmode_handler(coredev
->context
,
898 if (coredev
->mode
!= mode
&& coredev
->setmode_handler
)
899 rc
= coredev
->setmode_handler(coredev
->context
, mode
);
903 coredev
->mode
= mode
;
904 coredev
->device_flags
&= ~SMS_DEVICE_NOT_READY
;
908 sms_err("return error code %d.", rc
);
913 * calls device handler to get current mode of operation
915 * @param coredev pointer to a coredev object returned by
916 * smscore_register_device
918 * @return current mode
920 int smscore_get_device_mode(struct smscore_device_t
*coredev
)
922 return coredev
->mode
;
924 EXPORT_SYMBOL_GPL(smscore_get_device_mode
);
927 * find client by response id & type within the clients list.
928 * return client handle or NULL.
930 * @param coredev pointer to a coredev object returned by
931 * smscore_register_device
932 * @param data_type client data type (SMS_DONT_CARE for all types)
933 * @param id client id (SMS_DONT_CARE for all id)
937 smscore_client_t
*smscore_find_client(struct smscore_device_t
*coredev
,
938 int data_type
, int id
)
940 struct list_head
*first
;
941 struct smscore_client_t
*client
;
943 struct list_head
*firstid
;
944 struct smscore_idlist_t
*client_id
;
946 spin_lock_irqsave(&coredev
->clientslock
, flags
);
947 first
= &coredev
->clients
;
948 list_for_each_entry(client
, first
, entry
) {
949 firstid
= &client
->idlist
;
950 list_for_each_entry(client_id
, firstid
, entry
) {
951 if ((client_id
->id
== id
) &&
952 (client_id
->data_type
== data_type
||
953 (client_id
->data_type
== 0)))
959 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
964 * find client by response id/type, call clients onresponse handler
965 * return buffer to pool on error
967 * @param coredev pointer to a coredev object returned by
968 * smscore_register_device
969 * @param cb pointer to response buffer descriptor
972 void smscore_onresponse(struct smscore_device_t
*coredev
,
973 struct smscore_buffer_t
*cb
) {
974 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) ((u8
*) cb
->p
976 struct smscore_client_t
*client
;
978 static unsigned long last_sample_time
; /* = 0; */
979 static int data_total
; /* = 0; */
980 unsigned long time_now
= jiffies_to_msecs(jiffies
);
982 if (!last_sample_time
)
983 last_sample_time
= time_now
;
985 if (time_now
- last_sample_time
> 10000) {
986 sms_debug("\ndata rate %d bytes/secs",
987 (int)((data_total
* 1000) /
988 (time_now
- last_sample_time
)));
990 last_sample_time
= time_now
;
994 data_total
+= cb
->size
;
995 /* Do we need to re-route? */
996 if ((phdr
->msgType
== MSG_SMS_HO_PER_SLICES_IND
) ||
997 (phdr
->msgType
== MSG_SMS_TRANSMISSION_IND
)) {
998 if (coredev
->mode
== DEVICE_MODE_DVBT_BDA
)
999 phdr
->msgDstId
= DVBT_BDA_CONTROL_MSG_ID
;
1003 client
= smscore_find_client(coredev
, phdr
->msgType
, phdr
->msgDstId
);
1005 /* If no client registered for type & id,
1006 * check for control client where type is not registered */
1008 rc
= client
->onresponse_handler(client
->context
, cb
);
1011 switch (phdr
->msgType
) {
1012 case MSG_SMS_GET_VERSION_EX_RES
:
1014 struct SmsVersionRes_ST
*ver
=
1015 (struct SmsVersionRes_ST
*) phdr
;
1016 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1017 "id %d prots 0x%x ver %d.%d",
1018 ver
->FirmwareId
, ver
->SupportedProtocols
,
1019 ver
->RomVersionMajor
, ver
->RomVersionMinor
);
1021 coredev
->mode
= ver
->FirmwareId
== 255 ?
1022 DEVICE_MODE_NONE
: ver
->FirmwareId
;
1023 coredev
->modes_supported
= ver
->SupportedProtocols
;
1025 complete(&coredev
->version_ex_done
);
1028 case MSG_SMS_INIT_DEVICE_RES
:
1029 sms_debug("MSG_SMS_INIT_DEVICE_RES");
1030 complete(&coredev
->init_device_done
);
1032 case MSG_SW_RELOAD_START_RES
:
1033 sms_debug("MSG_SW_RELOAD_START_RES");
1034 complete(&coredev
->reload_start_done
);
1036 case MSG_SMS_DATA_DOWNLOAD_RES
:
1037 complete(&coredev
->data_download_done
);
1039 case MSG_SW_RELOAD_EXEC_RES
:
1040 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1042 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES
:
1043 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1044 complete(&coredev
->trigger_done
);
1046 case MSG_SMS_SLEEP_RESUME_COMP_IND
:
1047 complete(&coredev
->resume_done
);
1049 case MSG_SMS_GPIO_CONFIG_EX_RES
:
1050 sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1051 complete(&coredev
->gpio_configuration_done
);
1053 case MSG_SMS_GPIO_SET_LEVEL_RES
:
1054 sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1055 complete(&coredev
->gpio_set_level_done
);
1057 case MSG_SMS_GPIO_GET_LEVEL_RES
:
1059 u32
*msgdata
= (u32
*) phdr
;
1060 coredev
->gpio_get_res
= msgdata
[1];
1061 sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1062 coredev
->gpio_get_res
);
1063 complete(&coredev
->gpio_get_level_done
);
1066 case MSG_SMS_START_IR_RES
:
1067 complete(&coredev
->ir_init_done
);
1069 case MSG_SMS_IR_SAMPLES_IND
:
1070 sms_ir_event(coredev
,
1073 + sizeof(struct SmsMsgHdr_ST
)),
1074 (int)phdr
->msgLength
1075 - sizeof(struct SmsMsgHdr_ST
));
1081 smscore_putbuffer(coredev
, cb
);
1084 EXPORT_SYMBOL_GPL(smscore_onresponse
);
1087 * return pointer to next free buffer descriptor from core pool
1089 * @param coredev pointer to a coredev object returned by
1090 * smscore_register_device
1092 * @return pointer to descriptor on success, NULL on error.
1095 static struct smscore_buffer_t
*get_entry(struct smscore_device_t
*coredev
)
1097 struct smscore_buffer_t
*cb
= NULL
;
1098 unsigned long flags
;
1100 spin_lock_irqsave(&coredev
->bufferslock
, flags
);
1101 if (!list_empty(&coredev
->buffers
)) {
1102 cb
= (struct smscore_buffer_t
*) coredev
->buffers
.next
;
1103 list_del(&cb
->entry
);
1105 spin_unlock_irqrestore(&coredev
->bufferslock
, flags
);
1109 struct smscore_buffer_t
*smscore_getbuffer(struct smscore_device_t
*coredev
)
1111 struct smscore_buffer_t
*cb
= NULL
;
1113 wait_event(coredev
->buffer_mng_waitq
, (cb
= get_entry(coredev
)));
1117 EXPORT_SYMBOL_GPL(smscore_getbuffer
);
1120 * return buffer descriptor to a pool
1122 * @param coredev pointer to a coredev object returned by
1123 * smscore_register_device
1124 * @param cb pointer buffer descriptor
1127 void smscore_putbuffer(struct smscore_device_t
*coredev
,
1128 struct smscore_buffer_t
*cb
) {
1129 wake_up_interruptible(&coredev
->buffer_mng_waitq
);
1130 list_add_locked(&cb
->entry
, &coredev
->buffers
, &coredev
->bufferslock
);
1132 EXPORT_SYMBOL_GPL(smscore_putbuffer
);
1134 static int smscore_validate_client(struct smscore_device_t
*coredev
,
1135 struct smscore_client_t
*client
,
1136 int data_type
, int id
)
1138 struct smscore_idlist_t
*listentry
;
1139 struct smscore_client_t
*registered_client
;
1142 sms_err("bad parameter.");
1145 registered_client
= smscore_find_client(coredev
, data_type
, id
);
1146 if (registered_client
== client
)
1149 if (registered_client
) {
1150 sms_err("The msg ID already registered to another client.");
1153 listentry
= kzalloc(sizeof(struct smscore_idlist_t
), GFP_KERNEL
);
1155 sms_err("Can't allocate memory for client id.");
1159 listentry
->data_type
= data_type
;
1160 list_add_locked(&listentry
->entry
, &client
->idlist
,
1161 &coredev
->clientslock
);
1166 * creates smsclient object, check that id is taken by another client
1168 * @param coredev pointer to a coredev object from clients hotplug
1169 * @param initial_id all messages with this id would be sent to this client
1170 * @param data_type all messages of this type would be sent to this client
1171 * @param onresponse_handler client handler that is called to
1172 * process incoming messages
1173 * @param onremove_handler client handler that is called when device is removed
1174 * @param context client-specific context
1175 * @param client pointer to a value that receives created smsclient object
1177 * @return 0 on success, <0 on error.
1179 int smscore_register_client(struct smscore_device_t
*coredev
,
1180 struct smsclient_params_t
*params
,
1181 struct smscore_client_t
**client
)
1183 struct smscore_client_t
*newclient
;
1184 /* check that no other channel with same parameters exists */
1185 if (smscore_find_client(coredev
, params
->data_type
,
1186 params
->initial_id
)) {
1187 sms_err("Client already exist.");
1191 newclient
= kzalloc(sizeof(struct smscore_client_t
), GFP_KERNEL
);
1193 sms_err("Failed to allocate memory for client.");
1197 INIT_LIST_HEAD(&newclient
->idlist
);
1198 newclient
->coredev
= coredev
;
1199 newclient
->onresponse_handler
= params
->onresponse_handler
;
1200 newclient
->onremove_handler
= params
->onremove_handler
;
1201 newclient
->context
= params
->context
;
1202 list_add_locked(&newclient
->entry
, &coredev
->clients
,
1203 &coredev
->clientslock
);
1204 smscore_validate_client(coredev
, newclient
, params
->data_type
,
1205 params
->initial_id
);
1206 *client
= newclient
;
1207 sms_debug("%p %d %d", params
->context
, params
->data_type
,
1208 params
->initial_id
);
1212 EXPORT_SYMBOL_GPL(smscore_register_client
);
1215 * frees smsclient object and all subclients associated with it
1217 * @param client pointer to smsclient object returned by
1218 * smscore_register_client
1221 void smscore_unregister_client(struct smscore_client_t
*client
)
1223 struct smscore_device_t
*coredev
= client
->coredev
;
1224 unsigned long flags
;
1226 spin_lock_irqsave(&coredev
->clientslock
, flags
);
1229 while (!list_empty(&client
->idlist
)) {
1230 struct smscore_idlist_t
*identry
=
1231 (struct smscore_idlist_t
*) client
->idlist
.next
;
1232 list_del(&identry
->entry
);
1236 sms_info("%p", client
->context
);
1238 list_del(&client
->entry
);
1241 spin_unlock_irqrestore(&coredev
->clientslock
, flags
);
1243 EXPORT_SYMBOL_GPL(smscore_unregister_client
);
1246 * verifies that source id is not taken by another client,
1247 * calls device handler to send requests to the device
1249 * @param client pointer to smsclient object returned by
1250 * smscore_register_client
1251 * @param buffer pointer to a request buffer
1252 * @param size size (in bytes) of request buffer
1254 * @return 0 on success, <0 on error.
1256 int smsclient_sendrequest(struct smscore_client_t
*client
,
1257 void *buffer
, size_t size
)
1259 struct smscore_device_t
*coredev
;
1260 struct SmsMsgHdr_ST
*phdr
= (struct SmsMsgHdr_ST
*) buffer
;
1263 if (client
== NULL
) {
1264 sms_err("Got NULL client");
1268 coredev
= client
->coredev
;
1270 /* check that no other channel with same id exists */
1271 if (coredev
== NULL
) {
1272 sms_err("Got NULL coredev");
1276 rc
= smscore_validate_client(client
->coredev
, client
, 0,
1281 return coredev
->sendrequest_handler(coredev
->context
, buffer
, size
);
1283 EXPORT_SYMBOL_GPL(smsclient_sendrequest
);
1286 /* old GPIO managements implementation */
1287 int smscore_configure_gpio(struct smscore_device_t
*coredev
, u32 pin
,
1288 struct smscore_config_gpio
*pinconfig
)
1291 struct SmsMsgHdr_ST hdr
;
1295 if (coredev
->device_flags
& SMS_DEVICE_FAMILY2
) {
1296 msg
.hdr
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1297 msg
.hdr
.msgDstId
= HIF_TASK
;
1298 msg
.hdr
.msgFlags
= 0;
1299 msg
.hdr
.msgType
= MSG_SMS_GPIO_CONFIG_EX_REQ
;
1300 msg
.hdr
.msgLength
= sizeof(msg
);
1303 msg
.data
[1] = pinconfig
->pullupdown
;
1305 /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1306 msg
.data
[2] = pinconfig
->outputslewrate
== 0 ? 3 : 0;
1308 switch (pinconfig
->outputdriving
) {
1309 case SMS_GPIO_OUTPUTDRIVING_16mA
:
1310 msg
.data
[3] = 7; /* Nova - 16mA */
1312 case SMS_GPIO_OUTPUTDRIVING_12mA
:
1313 msg
.data
[3] = 5; /* Nova - 11mA */
1315 case SMS_GPIO_OUTPUTDRIVING_8mA
:
1316 msg
.data
[3] = 3; /* Nova - 7mA */
1318 case SMS_GPIO_OUTPUTDRIVING_4mA
:
1320 msg
.data
[3] = 2; /* Nova - 4mA */
1324 msg
.data
[4] = pinconfig
->direction
;
1326 } else /* TODO: SMS_DEVICE_FAMILY1 */
1329 return coredev
->sendrequest_handler(coredev
->context
,
1333 int smscore_set_gpio(struct smscore_device_t
*coredev
, u32 pin
, int level
)
1336 struct SmsMsgHdr_ST hdr
;
1340 if (pin
> MAX_GPIO_PIN_NUMBER
)
1343 msg
.hdr
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1344 msg
.hdr
.msgDstId
= HIF_TASK
;
1345 msg
.hdr
.msgFlags
= 0;
1346 msg
.hdr
.msgType
= MSG_SMS_GPIO_SET_LEVEL_REQ
;
1347 msg
.hdr
.msgLength
= sizeof(msg
);
1350 msg
.data
[1] = level
? 1 : 0;
1353 return coredev
->sendrequest_handler(coredev
->context
,
1357 /* new GPIO management implementation */
1358 static int GetGpioPinParams(u32 PinNum
, u32
*pTranslatedPinNum
,
1359 u32
*pGroupNum
, u32
*pGroupCfg
) {
1364 *pTranslatedPinNum
= 0;
1367 } else if (PinNum
>= 2 && PinNum
<= 6) {
1368 *pTranslatedPinNum
= 2;
1371 } else if (PinNum
>= 7 && PinNum
<= 11) {
1372 *pTranslatedPinNum
= 7;
1374 } else if (PinNum
>= 12 && PinNum
<= 15) {
1375 *pTranslatedPinNum
= 12;
1378 } else if (PinNum
== 16) {
1379 *pTranslatedPinNum
= 16;
1381 } else if (PinNum
>= 17 && PinNum
<= 24) {
1382 *pTranslatedPinNum
= 17;
1384 } else if (PinNum
== 25) {
1385 *pTranslatedPinNum
= 25;
1387 } else if (PinNum
>= 26 && PinNum
<= 28) {
1388 *pTranslatedPinNum
= 26;
1390 } else if (PinNum
== 29) {
1391 *pTranslatedPinNum
= 29;
1394 } else if (PinNum
== 30) {
1395 *pTranslatedPinNum
= 30;
1397 } else if (PinNum
== 31) {
1398 *pTranslatedPinNum
= 31;
1408 int smscore_gpio_configure(struct smscore_device_t
*coredev
, u8 PinNum
,
1409 struct smscore_gpio_config
*pGpioConfig
) {
1412 u32 TranslatedPinNum
= 0;
1420 struct SmsMsgHdr_ST xMsgHeader
;
1425 if (PinNum
> MAX_GPIO_PIN_NUMBER
)
1428 if (pGpioConfig
== NULL
)
1431 totalLen
= sizeof(struct SmsMsgHdr_ST
) + (sizeof(u32
) * 6);
1433 buffer
= kmalloc(totalLen
+ SMS_DMA_ALIGNMENT
,
1434 GFP_KERNEL
| GFP_DMA
);
1438 pMsg
= (struct SetGpioMsg
*) SMS_ALIGN_ADDRESS(buffer
);
1440 pMsg
->xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1441 pMsg
->xMsgHeader
.msgDstId
= HIF_TASK
;
1442 pMsg
->xMsgHeader
.msgFlags
= 0;
1443 pMsg
->xMsgHeader
.msgLength
= (u16
) totalLen
;
1444 pMsg
->msgData
[0] = PinNum
;
1446 if (!(coredev
->device_flags
& SMS_DEVICE_FAMILY2
)) {
1447 pMsg
->xMsgHeader
.msgType
= MSG_SMS_GPIO_CONFIG_REQ
;
1448 if (GetGpioPinParams(PinNum
, &TranslatedPinNum
, &GroupNum
,
1454 pMsg
->msgData
[1] = TranslatedPinNum
;
1455 pMsg
->msgData
[2] = GroupNum
;
1456 ElectricChar
= (pGpioConfig
->PullUpDown
)
1457 | (pGpioConfig
->InputCharacteristics
<< 2)
1458 | (pGpioConfig
->OutputSlewRate
<< 3)
1459 | (pGpioConfig
->OutputDriving
<< 4);
1460 pMsg
->msgData
[3] = ElectricChar
;
1461 pMsg
->msgData
[4] = pGpioConfig
->Direction
;
1462 pMsg
->msgData
[5] = groupCfg
;
1464 pMsg
->xMsgHeader
.msgType
= MSG_SMS_GPIO_CONFIG_EX_REQ
;
1465 pMsg
->msgData
[1] = pGpioConfig
->PullUpDown
;
1466 pMsg
->msgData
[2] = pGpioConfig
->OutputSlewRate
;
1467 pMsg
->msgData
[3] = pGpioConfig
->OutputDriving
;
1468 pMsg
->msgData
[4] = pGpioConfig
->Direction
;
1469 pMsg
->msgData
[5] = 0;
1472 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)pMsg
);
1473 rc
= smscore_sendrequest_and_wait(coredev
, pMsg
, totalLen
,
1474 &coredev
->gpio_configuration_done
);
1478 sms_err("smscore_gpio_configure timeout");
1480 sms_err("smscore_gpio_configure error");
1488 int smscore_gpio_set_level(struct smscore_device_t
*coredev
, u8 PinNum
,
1496 struct SmsMsgHdr_ST xMsgHeader
;
1497 u32 msgData
[3]; /* keep it 3 ! */
1500 if ((NewLevel
> 1) || (PinNum
> MAX_GPIO_PIN_NUMBER
))
1503 totalLen
= sizeof(struct SmsMsgHdr_ST
) +
1504 (3 * sizeof(u32
)); /* keep it 3 ! */
1506 buffer
= kmalloc(totalLen
+ SMS_DMA_ALIGNMENT
,
1507 GFP_KERNEL
| GFP_DMA
);
1511 pMsg
= (struct SetGpioMsg
*) SMS_ALIGN_ADDRESS(buffer
);
1513 pMsg
->xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1514 pMsg
->xMsgHeader
.msgDstId
= HIF_TASK
;
1515 pMsg
->xMsgHeader
.msgFlags
= 0;
1516 pMsg
->xMsgHeader
.msgType
= MSG_SMS_GPIO_SET_LEVEL_REQ
;
1517 pMsg
->xMsgHeader
.msgLength
= (u16
) totalLen
;
1518 pMsg
->msgData
[0] = PinNum
;
1519 pMsg
->msgData
[1] = NewLevel
;
1521 /* Send message to SMS */
1522 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)pMsg
);
1523 rc
= smscore_sendrequest_and_wait(coredev
, pMsg
, totalLen
,
1524 &coredev
->gpio_set_level_done
);
1528 sms_err("smscore_gpio_set_level timeout");
1530 sms_err("smscore_gpio_set_level error");
1537 int smscore_gpio_get_level(struct smscore_device_t
*coredev
, u8 PinNum
,
1545 struct SmsMsgHdr_ST xMsgHeader
;
1550 if (PinNum
> MAX_GPIO_PIN_NUMBER
)
1553 totalLen
= sizeof(struct SmsMsgHdr_ST
) + (2 * sizeof(u32
));
1555 buffer
= kmalloc(totalLen
+ SMS_DMA_ALIGNMENT
,
1556 GFP_KERNEL
| GFP_DMA
);
1560 pMsg
= (struct SetGpioMsg
*) SMS_ALIGN_ADDRESS(buffer
);
1562 pMsg
->xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
1563 pMsg
->xMsgHeader
.msgDstId
= HIF_TASK
;
1564 pMsg
->xMsgHeader
.msgFlags
= 0;
1565 pMsg
->xMsgHeader
.msgType
= MSG_SMS_GPIO_GET_LEVEL_REQ
;
1566 pMsg
->xMsgHeader
.msgLength
= (u16
) totalLen
;
1567 pMsg
->msgData
[0] = PinNum
;
1568 pMsg
->msgData
[1] = 0;
1570 /* Send message to SMS */
1571 smsendian_handle_tx_message((struct SmsMsgHdr_ST
*)pMsg
);
1572 rc
= smscore_sendrequest_and_wait(coredev
, pMsg
, totalLen
,
1573 &coredev
->gpio_get_level_done
);
1577 sms_err("smscore_gpio_get_level timeout");
1579 sms_err("smscore_gpio_get_level error");
1583 /* Its a race between other gpio_get_level() and the copy of the single
1584 * global 'coredev->gpio_get_res' to the function's variable 'level'
1586 *level
= coredev
->gpio_get_res
;
1591 static int __init
smscore_module_init(void)
1595 INIT_LIST_HEAD(&g_smscore_notifyees
);
1596 INIT_LIST_HEAD(&g_smscore_devices
);
1597 kmutex_init(&g_smscore_deviceslock
);
1599 INIT_LIST_HEAD(&g_smscore_registry
);
1600 kmutex_init(&g_smscore_registrylock
);
1605 static void __exit
smscore_module_exit(void)
1607 kmutex_lock(&g_smscore_deviceslock
);
1608 while (!list_empty(&g_smscore_notifyees
)) {
1609 struct smscore_device_notifyee_t
*notifyee
=
1610 (struct smscore_device_notifyee_t
*)
1611 g_smscore_notifyees
.next
;
1613 list_del(¬ifyee
->entry
);
1616 kmutex_unlock(&g_smscore_deviceslock
);
1618 kmutex_lock(&g_smscore_registrylock
);
1619 while (!list_empty(&g_smscore_registry
)) {
1620 struct smscore_registry_entry_t
*entry
=
1621 (struct smscore_registry_entry_t
*)
1622 g_smscore_registry
.next
;
1624 list_del(&entry
->entry
);
1627 kmutex_unlock(&g_smscore_registrylock
);
1632 module_init(smscore_module_init
);
1633 module_exit(smscore_module_exit
);
1635 MODULE_DESCRIPTION("Siano MDTV Core module");
1636 MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1637 MODULE_LICENSE("GPL");