V4L/DVB (10751): sms1xxx: fix checkpatch.pl violations introduced by previous changeset
[linux-2.6/linux-2.6-openrd.git] / drivers / media / dvb / siano / smscoreapi.c
blobd2669c8408ea2ea1f8c85888df745cf0c8e96b97
1 /*
2 * Siano core API module
4 * This file contains implementation for the interface to sms core component
6 * author: Uri Shkolnik
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>
30 #include <linux/io.h>
32 #include <linux/firmware.h>
34 #include "smscoreapi.h"
35 #include "sms-cards.h"
37 int sms_dbg;
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;
43 hotplug_t hotplug;
46 struct smscore_idlist_t {
47 struct list_head entry;
48 int id;
49 int data_type;
52 struct smscore_client_t {
53 struct list_head entry;
54 struct smscore_device_t *coredev;
55 void *context;
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;
70 int num_buffers;
72 void *common_buffer;
73 int common_buffer_size;
74 dma_addr_t common_buffer_phys;
76 void *context;
77 struct device *device;
79 char devpath[32];
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;
93 int board_id;
94 int led_state;
97 void smscore_set_board_id(struct smscore_device_t *core, int id)
99 core->board_id = id;
102 int smscore_led_state(struct smscore_device_t *core, int led)
104 if (led >= 0)
105 core->led_state = led;
106 return core->led_state;
108 EXPORT_SYMBOL(smscore_set_board_id);
110 int smscore_get_board_id(struct smscore_device_t *core)
112 return core->board_id;
114 EXPORT_SYMBOL(smscore_get_board_id);
116 struct smscore_registry_entry_t {
117 struct list_head entry;
118 char devpath[32];
119 int mode;
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;
143 next = next->next) {
144 entry = (struct smscore_registry_entry_t *) next;
145 if (!strcmp(entry->devpath, devpath)) {
146 kmutex_unlock(&g_smscore_registrylock);
147 return entry;
150 entry = (struct smscore_registry_entry_t *)
151 kmalloc(sizeof(struct smscore_registry_entry_t),
152 GFP_KERNEL);
153 if (entry) {
154 entry->mode = default_mode;
155 strcpy(entry->devpath, devpath);
156 list_add(&entry->entry, &g_smscore_registry);
157 } else
158 sms_err("failed to create smscore_registry.");
159 kmutex_unlock(&g_smscore_registrylock);
160 return entry;
163 int smscore_registry_getmode(char *devpath)
165 struct smscore_registry_entry_t *entry;
167 entry = smscore_find_registry(devpath);
168 if (entry)
169 return entry->mode;
170 else
171 sms_err("No registry found.");
173 return default_mode;
175 EXPORT_SYMBOL(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);
182 if (entry)
183 return entry->type;
184 else
185 sms_err("No registry found.");
187 return -1;
190 void smscore_registry_setmode(char *devpath, int mode)
192 struct smscore_registry_entry_t *entry;
194 entry = smscore_find_registry(devpath);
195 if (entry)
196 entry->mode = mode;
197 else
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);
207 if (entry)
208 entry->type = type;
209 else
210 sms_err("No registry found.");
214 static void list_add_locked(struct list_head *new, struct list_head *head,
215 spinlock_t *lock)
217 unsigned long flags;
219 spin_lock_irqsave(lock, flags);
221 list_add(new, head);
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;
238 int rc = 0;
240 kmutex_lock(&g_smscore_deviceslock);
242 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
243 GFP_KERNEL);
244 if (notifyee) {
245 /* now notify callback about existing devices */
246 first = &g_smscore_devices;
247 for (next = first->next;
248 next != first && !rc;
249 next = next->next) {
250 struct smscore_device_t *coredev =
251 (struct smscore_device_t *) next;
252 rc = hotplug(coredev, coredev->device, 1);
255 if (rc >= 0) {
256 notifyee->hotplug = hotplug;
257 list_add(&notifyee->entry, &g_smscore_notifyees);
258 } else
259 kfree(notifyee);
260 } else
261 rc = -ENOMEM;
263 kmutex_unlock(&g_smscore_deviceslock);
265 return rc;
267 EXPORT_SYMBOL(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;
286 next = next->next;
288 if (notifyee->hotplug == hotplug) {
289 list_del(&notifyee->entry);
290 kfree(notifyee);
294 kmutex_unlock(&g_smscore_deviceslock);
296 EXPORT_SYMBOL(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;
313 int rc = 0;
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);
322 if (rc < 0)
323 break;
326 return rc;
329 static struct
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);
335 if (!cb) {
336 sms_info("kmalloc(...) failed");
337 return NULL;
340 cb->p = buffer;
341 cb->offset_in_common = buffer - (u8 *) common_buffer;
342 cb->phys = common_buffer_phys + cb->offset_in_common;
344 return cb;
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
352 * and handlers
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;
361 u8 *buffer;
363 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
364 if (!dev) {
365 sms_info("kzalloc(...) failed");
366 return -ENOMEM;
369 /* init list entry so it could be safe in smscore_unregister_device */
370 INIT_LIST_HEAD(&dev->entry);
372 /* init queues */
373 INIT_LIST_HEAD(&dev->clients);
374 INIT_LIST_HEAD(&dev->buffers);
376 /* init locks */
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);
395 return -ENOMEM;
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);
405 if (!cb) {
406 smscore_unregister_device(dev);
407 return -ENOMEM;
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);
434 *coredev = dev;
436 sms_info("device %p created", dev);
438 return 0;
440 EXPORT_SYMBOL(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));
454 if (rc < 0) {
455 sms_info("set device mode faile , rc %d", rc);
456 return 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);
467 return rc;
469 EXPORT_SYMBOL(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);
476 if (rc < 0) {
477 sms_info("sendrequest returned error %d", rc);
478 return rc;
481 return wait_for_completion_timeout(completion,
482 msecs_to_jiffies(10000)) ?
483 0 : -ETIME;
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;
493 int rc = 0;
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);
499 if (rc < 0)
500 return rc;
503 /* PAGE_SIZE buffer shall be enough and dma aligned */
504 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
505 if (!msg)
506 return -ENOMEM;
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,
513 msg->msgLength,
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);
535 else
536 rc = smscore_sendrequest_and_wait(
537 coredev, DataMsg,
538 DataMsg->xMsgHeader.msgLength,
539 &coredev->data_download_done);
541 payload += payload_size;
542 size -= payload_size;
543 mem_address += payload_size;
546 if (rc >= 0) {
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) +
553 sizeof(u32) * 5);
555 TriggerMsg->msgData[0] = firmware->StartAddress;
556 /* Entry point */
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);
566 msleep(100);
567 } else
568 rc = smscore_sendrequest_and_wait(
569 coredev, TriggerMsg,
570 TriggerMsg->xMsgHeader.msgLength,
571 &coredev->trigger_done);
572 } else {
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);
579 msleep(500);
582 sms_debug("rc=%d, postload=%p ", rc,
583 coredev->postload_handler);
585 kfree(msg);
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,
603 char *filename,
604 loadfirmware_t loadfirmware_handler)
606 int rc = -ENOENT;
607 const struct firmware *fw;
608 u8 *fw_buffer;
610 if (loadfirmware_handler == NULL && !(coredev->device_flags &
611 SMS_DEVICE_FAMILY2))
612 return -EINVAL;
614 rc = request_firmware(&fw, filename, coredev->device);
615 if (rc < 0) {
616 sms_info("failed to open \"%s\"", filename);
617 return rc;
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);
622 if (fw_buffer) {
623 memcpy(fw_buffer, fw->data, fw->size);
625 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
626 smscore_load_firmware_family2(coredev,
627 fw_buffer,
628 fw->size) :
629 loadfirmware_handler(coredev->context,
630 fw_buffer, fw->size);
632 kfree(fw_buffer);
633 } else {
634 sms_info("failed to allocate firmware buffer");
635 rc = -ENOMEM;
638 release_firmware(fw);
640 return rc;
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;
655 int num_buffers = 0;
656 int retry = 0;
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 */
666 while (1) {
667 while ((cb = smscore_getbuffer(coredev))) {
668 kfree(cb);
669 num_buffers++;
671 if (num_buffers == coredev->num_buffers)
672 break;
673 if (++retry > 10) {
674 sms_info("exiting although "
675 "not all buffers released.");
676 break;
679 sms_info("waiting for %d buffer(s)",
680 coredev->num_buffers - num_buffers);
681 msleep(100);
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);
692 kfree(coredev);
694 kmutex_unlock(&g_smscore_deviceslock);
696 sms_info("device %p destroyed", coredev);
698 EXPORT_SYMBOL(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);
706 int rc;
708 if (!buffer)
709 return -ENOMEM;
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);
716 if (rc == -ETIME) {
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);
724 if (rc < 0)
725 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
726 "second try, rc %d", rc);
727 } else
728 rc = -ETIME;
731 kfree(buffer);
733 return rc;
736 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
737 /*Stellar NOVA A0 Nova B0 VEGA*/
738 /*DVBT*/
739 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
740 /*DVBH*/
741 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
742 /*TDMB*/
743 {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
744 /*DABIP*/
745 {"none", "none", "none", "none"},
746 /*BDA*/
747 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
748 /*ISDBT*/
749 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
750 /*ISDBTBDA*/
751 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
752 /*CMMB*/
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)
775 void *buffer;
776 int rc = 0;
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);
783 return -EINVAL;
786 smscore_registry_setmode(coredev->devpath, mode);
788 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
789 rc = smscore_detect_mode(coredev);
790 if (rc < 0) {
791 sms_err("mode detect failed %d", rc);
792 return rc;
796 if (coredev->mode == mode) {
797 sms_info("device mode %d already set", mode);
798 return 0;
801 if (!(coredev->modes_supported & (1 << mode))) {
802 char *fw_filename;
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,
808 fw_filename, NULL);
809 if (rc < 0) {
810 sms_warn("error %d loading firmware: %s, "
811 "trying again with default firmware",
812 rc, fw_filename);
814 /* try again with the default firmware */
815 fw_filename = smscore_fw_lkup[mode][type];
816 rc = smscore_load_firmware_from_file(coredev,
817 fw_filename, NULL);
819 if (rc < 0) {
820 sms_warn("error %d loading "
821 "firmware: %s", rc,
822 fw_filename);
823 return rc;
826 sms_log("firmware download success: %s", fw_filename);
827 } else
828 sms_info("mode %d supported by running "
829 "firmware", mode);
831 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
832 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
833 if (buffer) {
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);
846 kfree(buffer);
847 } else {
848 sms_err("Could not allocate buffer for "
849 "init device message.");
850 rc = -ENOMEM;
852 } else {
853 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
854 sms_err("invalid mode specified %d", mode);
855 return -EINVAL;
858 smscore_registry_setmode(coredev->devpath, mode);
860 if (coredev->detectmode_handler)
861 coredev->detectmode_handler(coredev->context,
862 &coredev->mode);
864 if (coredev->mode != mode && coredev->setmode_handler)
865 rc = coredev->setmode_handler(coredev->context, mode);
868 if (rc >= 0) {
869 coredev->mode = mode;
870 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
873 if (rc != 0)
874 sms_err("return error code %d.", rc);
875 return 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(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)
902 static struct
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;
908 unsigned long flags;
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;
916 next = next->next) {
917 firstid = &((struct smscore_client_t *)next)->idlist;
918 for (nextid = firstid->next;
919 nextid != firstid;
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;
925 break;
929 spin_unlock_irqrestore(&coredev->clientslock, flags);
930 return client;
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);
949 int rc = -EBUSY;
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;
964 data_total = 0;
967 data_total += cb->size;
968 /* If no client registered for type & id,
969 * check for control client where type is not registered */
970 if (client)
971 rc = client->onresponse_handler(client->context, cb);
973 if (rc < 0) {
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);
989 break;
991 case MSG_SMS_INIT_DEVICE_RES:
992 sms_debug("MSG_SMS_INIT_DEVICE_RES");
993 complete(&coredev->init_device_done);
994 break;
995 case MSG_SW_RELOAD_START_RES:
996 sms_debug("MSG_SW_RELOAD_START_RES");
997 complete(&coredev->reload_start_done);
998 break;
999 case MSG_SMS_DATA_DOWNLOAD_RES:
1000 complete(&coredev->data_download_done);
1001 break;
1002 case MSG_SW_RELOAD_EXEC_RES:
1003 sms_debug("MSG_SW_RELOAD_EXEC_RES");
1004 break;
1005 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1006 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1007 complete(&coredev->trigger_done);
1008 break;
1009 case MSG_SMS_SLEEP_RESUME_COMP_IND:
1010 complete(&coredev->resume_done);
1011 break;
1012 default:
1013 break;
1015 smscore_putbuffer(coredev, cb);
1018 EXPORT_SYMBOL(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);
1042 return cb;
1044 EXPORT_SYMBOL(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(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;
1068 if (!client) {
1069 sms_err("bad parameter.");
1070 return -EFAULT;
1072 registered_client = smscore_find_client(coredev, data_type, id);
1073 if (registered_client == client)
1074 return 0;
1076 if (registered_client) {
1077 sms_err("The msg ID already registered to another client.");
1078 return -EEXIST;
1080 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1081 if (!listentry) {
1082 sms_err("Can't allocate memory for client id.");
1083 return -ENOMEM;
1085 listentry->id = id;
1086 listentry->data_type = data_type;
1087 list_add_locked(&listentry->entry, &client->idlist,
1088 &coredev->clientslock);
1089 return 0;
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.");
1115 return -EEXIST;
1118 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1119 if (!newclient) {
1120 sms_err("Failed to allocate memory for client.");
1121 return -ENOMEM;
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);
1137 return 0;
1139 EXPORT_SYMBOL(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);
1160 kfree(identry);
1163 sms_info("%p", client->context);
1165 list_del(&client->entry);
1166 kfree(client);
1168 spin_unlock_irqrestore(&coredev->clientslock, flags);
1170 EXPORT_SYMBOL(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;
1188 int rc;
1190 if (client == NULL) {
1191 sms_err("Got NULL client");
1192 return -EINVAL;
1195 coredev = client->coredev;
1197 /* check that no other channel with same id exists */
1198 if (coredev == NULL) {
1199 sms_err("Got NULL coredev");
1200 return -EINVAL;
1203 rc = smscore_validate_client(client->coredev, client, 0,
1204 phdr->msgSrcId);
1205 if (rc < 0)
1206 return rc;
1208 return coredev->sendrequest_handler(coredev->context, buffer, size);
1210 EXPORT_SYMBOL(smsclient_sendrequest);
1213 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1214 struct smscore_gpio_config *pinconfig)
1216 struct {
1217 struct SmsMsgHdr_ST hdr;
1218 u32 data[6];
1219 } msg;
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);
1228 msg.data[0] = pin;
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 */
1237 break;
1238 case SMS_GPIO_OUTPUTDRIVING_12mA:
1239 msg.data[3] = 5; /* Nova - 11mA */
1240 break;
1241 case SMS_GPIO_OUTPUTDRIVING_8mA:
1242 msg.data[3] = 3; /* Nova - 7mA */
1243 break;
1244 case SMS_GPIO_OUTPUTDRIVING_4mA:
1245 default:
1246 msg.data[3] = 2; /* Nova - 4mA */
1247 break;
1250 msg.data[4] = pinconfig->direction;
1251 msg.data[5] = 0;
1252 } else /* TODO: SMS_DEVICE_FAMILY1 */
1253 return -EINVAL;
1255 return coredev->sendrequest_handler(coredev->context,
1256 &msg, sizeof(msg));
1259 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1261 struct {
1262 struct SmsMsgHdr_ST hdr;
1263 u32 data[3];
1264 } msg;
1266 if (pin > MAX_GPIO_PIN_NUMBER)
1267 return -EINVAL;
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);
1275 msg.data[0] = pin;
1276 msg.data[1] = level ? 1 : 0;
1277 msg.data[2] = 0;
1279 return coredev->sendrequest_handler(coredev->context,
1280 &msg, sizeof(msg));
1283 static int __init smscore_module_init(void)
1285 int rc = 0;
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);
1299 return rc;
1300 sms_debug("rc %d", rc);
1302 return 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(&notifyee->entry);
1319 kfree(notifyee);
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);
1330 kfree(entry);
1332 kmutex_unlock(&g_smscore_registrylock);
1334 sms_debug("");
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");