V4L/DVB (8453): sms1xxx: dvb/siano/: cleanups
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / media / dvb / siano / smscoreapi.c
blobc5f45fed69dc41290a2300a5a90dfea701f87cdb
1 /*
2 * Siano core API module
4 * This file contains implementation for the interface to sms core component
6 * author: Anatoly Greenblat
8 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 3 as
12 * published by the Free Software Foundation;
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
17 * See the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/moduleparam.h>
28 #include <linux/dma-mapping.h>
29 #include <linux/delay.h>
30 #include <linux/io.h>
32 #include <linux/firmware.h>
34 #include "smscoreapi.h"
35 #include "sms-cards.h"
37 int sms_debug;
38 module_param_named(debug, sms_debug, 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;
96 void smscore_set_board_id(struct smscore_device_t *core, int id)
98 core->board_id = id;
101 int smscore_get_board_id(struct smscore_device_t *core)
103 return core->board_id;
106 struct smscore_registry_entry_t {
107 struct list_head entry;
108 char devpath[32];
109 int mode;
110 enum sms_device_type_st type;
113 static struct list_head g_smscore_notifyees;
114 static struct list_head g_smscore_devices;
115 static struct mutex g_smscore_deviceslock;
117 static struct list_head g_smscore_registry;
118 static struct mutex g_smscore_registrylock;
120 static int default_mode = 4;
122 module_param(default_mode, int, 0644);
123 MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
125 static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
127 struct smscore_registry_entry_t *entry;
128 struct list_head *next;
130 kmutex_lock(&g_smscore_registrylock);
131 for (next = g_smscore_registry.next;
132 next != &g_smscore_registry;
133 next = next->next) {
134 entry = (struct smscore_registry_entry_t *) next;
135 if (!strcmp(entry->devpath, devpath)) {
136 kmutex_unlock(&g_smscore_registrylock);
137 return entry;
140 entry = (struct smscore_registry_entry_t *)
141 kmalloc(sizeof(struct smscore_registry_entry_t),
142 GFP_KERNEL);
143 if (entry) {
144 entry->mode = default_mode;
145 strcpy(entry->devpath, devpath);
146 list_add(&entry->entry, &g_smscore_registry);
147 } else
148 sms_err("failed to create smscore_registry.");
149 kmutex_unlock(&g_smscore_registrylock);
150 return entry;
153 int smscore_registry_getmode(char *devpath)
155 struct smscore_registry_entry_t *entry;
157 entry = smscore_find_registry(devpath);
158 if (entry)
159 return entry->mode;
160 else
161 sms_err("No registry found.");
163 return default_mode;
166 static enum sms_device_type_st smscore_registry_gettype(char *devpath)
168 struct smscore_registry_entry_t *entry;
170 entry = smscore_find_registry(devpath);
171 if (entry)
172 return entry->type;
173 else
174 sms_err("No registry found.");
176 return -1;
179 void smscore_registry_setmode(char *devpath, int mode)
181 struct smscore_registry_entry_t *entry;
183 entry = smscore_find_registry(devpath);
184 if (entry)
185 entry->mode = mode;
186 else
187 sms_err("No registry found.");
190 static void smscore_registry_settype(char *devpath,
191 enum sms_device_type_st type)
193 struct smscore_registry_entry_t *entry;
195 entry = smscore_find_registry(devpath);
196 if (entry)
197 entry->type = type;
198 else
199 sms_err("No registry found.");
203 static void list_add_locked(struct list_head *new, struct list_head *head,
204 spinlock_t *lock)
206 unsigned long flags;
208 spin_lock_irqsave(lock, flags);
210 list_add(new, head);
212 spin_unlock_irqrestore(lock, flags);
216 * register a client callback that called when device plugged in/unplugged
217 * NOTE: if devices exist callback is called immediately for each device
219 * @param hotplug callback
221 * @return 0 on success, <0 on error.
223 int smscore_register_hotplug(hotplug_t hotplug)
225 struct smscore_device_notifyee_t *notifyee;
226 struct list_head *next, *first;
227 int rc = 0;
229 kmutex_lock(&g_smscore_deviceslock);
231 notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
232 GFP_KERNEL);
233 if (notifyee) {
234 /* now notify callback about existing devices */
235 first = &g_smscore_devices;
236 for (next = first->next;
237 next != first && !rc;
238 next = next->next) {
239 struct smscore_device_t *coredev =
240 (struct smscore_device_t *) next;
241 rc = hotplug(coredev, coredev->device, 1);
244 if (rc >= 0) {
245 notifyee->hotplug = hotplug;
246 list_add(&notifyee->entry, &g_smscore_notifyees);
247 } else
248 kfree(notifyee);
249 } else
250 rc = -ENOMEM;
252 kmutex_unlock(&g_smscore_deviceslock);
254 return rc;
258 * unregister a client callback that called when device plugged in/unplugged
260 * @param hotplug callback
263 void smscore_unregister_hotplug(hotplug_t hotplug)
265 struct list_head *next, *first;
267 kmutex_lock(&g_smscore_deviceslock);
269 first = &g_smscore_notifyees;
271 for (next = first->next; next != first;) {
272 struct smscore_device_notifyee_t *notifyee =
273 (struct smscore_device_notifyee_t *) next;
274 next = next->next;
276 if (notifyee->hotplug == hotplug) {
277 list_del(&notifyee->entry);
278 kfree(notifyee);
282 kmutex_unlock(&g_smscore_deviceslock);
285 static void smscore_notify_clients(struct smscore_device_t *coredev)
287 struct smscore_client_t *client;
289 /* the client must call smscore_unregister_client from remove handler */
290 while (!list_empty(&coredev->clients)) {
291 client = (struct smscore_client_t *) coredev->clients.next;
292 client->onremove_handler(client->context);
296 static int smscore_notify_callbacks(struct smscore_device_t *coredev,
297 struct device *device, int arrival)
299 struct list_head *next, *first;
300 int rc = 0;
302 /* note: must be called under g_deviceslock */
304 first = &g_smscore_notifyees;
306 for (next = first->next; next != first; next = next->next) {
307 rc = ((struct smscore_device_notifyee_t *) next)->
308 hotplug(coredev, device, arrival);
309 if (rc < 0)
310 break;
313 return rc;
316 static struct
317 smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
318 dma_addr_t common_buffer_phys)
320 struct smscore_buffer_t *cb =
321 kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
322 if (!cb) {
323 sms_info("kmalloc(...) failed");
324 return NULL;
327 cb->p = buffer;
328 cb->offset_in_common = buffer - (u8 *) common_buffer;
329 cb->phys = common_buffer_phys + cb->offset_in_common;
331 return cb;
335 * creates coredev object for a device, prepares buffers,
336 * creates buffer mappings, notifies registered hotplugs about new device.
338 * @param params device pointer to struct with device specific parameters
339 * and handlers
340 * @param coredev pointer to a value that receives created coredev object
342 * @return 0 on success, <0 on error.
344 int smscore_register_device(struct smsdevice_params_t *params,
345 struct smscore_device_t **coredev)
347 struct smscore_device_t *dev;
348 u8 *buffer;
350 dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
351 if (!dev) {
352 sms_info("kzalloc(...) failed");
353 return -ENOMEM;
356 /* init list entry so it could be safe in smscore_unregister_device */
357 INIT_LIST_HEAD(&dev->entry);
359 /* init queues */
360 INIT_LIST_HEAD(&dev->clients);
361 INIT_LIST_HEAD(&dev->buffers);
363 /* init locks */
364 spin_lock_init(&dev->clientslock);
365 spin_lock_init(&dev->bufferslock);
367 /* init completion events */
368 init_completion(&dev->version_ex_done);
369 init_completion(&dev->data_download_done);
370 init_completion(&dev->trigger_done);
371 init_completion(&dev->init_device_done);
372 init_completion(&dev->reload_start_done);
373 init_completion(&dev->resume_done);
375 /* alloc common buffer */
376 dev->common_buffer_size = params->buffer_size * params->num_buffers;
377 dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
378 &dev->common_buffer_phys,
379 GFP_KERNEL | GFP_DMA);
380 if (!dev->common_buffer) {
381 smscore_unregister_device(dev);
382 return -ENOMEM;
385 /* prepare dma buffers */
386 for (buffer = dev->common_buffer;
387 dev->num_buffers < params->num_buffers;
388 dev->num_buffers++, buffer += params->buffer_size) {
389 struct smscore_buffer_t *cb =
390 smscore_createbuffer(buffer, dev->common_buffer,
391 dev->common_buffer_phys);
392 if (!cb) {
393 smscore_unregister_device(dev);
394 return -ENOMEM;
397 smscore_putbuffer(dev, cb);
400 sms_info("allocated %d buffers", dev->num_buffers);
402 dev->mode = DEVICE_MODE_NONE;
403 dev->context = params->context;
404 dev->device = params->device;
405 dev->setmode_handler = params->setmode_handler;
406 dev->detectmode_handler = params->detectmode_handler;
407 dev->sendrequest_handler = params->sendrequest_handler;
408 dev->preload_handler = params->preload_handler;
409 dev->postload_handler = params->postload_handler;
411 dev->device_flags = params->flags;
412 strcpy(dev->devpath, params->devpath);
414 smscore_registry_settype(dev->devpath, params->device_type);
416 /* add device to devices list */
417 kmutex_lock(&g_smscore_deviceslock);
418 list_add(&dev->entry, &g_smscore_devices);
419 kmutex_unlock(&g_smscore_deviceslock);
421 *coredev = dev;
423 sms_info("device %p created", dev);
425 return 0;
429 * sets initial device mode and notifies client hotplugs that device is ready
431 * @param coredev pointer to a coredev object returned by
432 * smscore_register_device
434 * @return 0 on success, <0 on error.
436 int smscore_start_device(struct smscore_device_t *coredev)
438 int rc = smscore_set_device_mode(
439 coredev, smscore_registry_getmode(coredev->devpath));
440 if (rc < 0) {
441 sms_info("set device mode faile , rc %d", rc);
442 return rc;
445 kmutex_lock(&g_smscore_deviceslock);
447 rc = smscore_notify_callbacks(coredev, coredev->device, 1);
449 sms_info("device %p started, rc %d", coredev, rc);
451 kmutex_unlock(&g_smscore_deviceslock);
453 return rc;
456 static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
457 void *buffer, size_t size,
458 struct completion *completion)
460 int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
461 if (rc < 0) {
462 sms_info("sendrequest returned error %d", rc);
463 return rc;
466 return wait_for_completion_timeout(completion,
467 msecs_to_jiffies(10000)) ?
468 0 : -ETIME;
471 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
472 void *buffer, size_t size)
474 struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
475 struct SmsMsgHdr_ST *msg;
476 u32 mem_address = firmware->StartAddress;
477 u8 *payload = firmware->Payload;
478 int rc = 0;
480 sms_info("loading FW to addr 0x%x size %d",
481 mem_address, firmware->Length);
482 if (coredev->preload_handler) {
483 rc = coredev->preload_handler(coredev->context);
484 if (rc < 0)
485 return rc;
488 /* PAGE_SIZE buffer shall be enough and dma aligned */
489 msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
490 if (!msg)
491 return -ENOMEM;
493 if (coredev->mode != DEVICE_MODE_NONE) {
494 sms_debug("sending reload command.");
495 SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
496 sizeof(struct SmsMsgHdr_ST));
497 rc = smscore_sendrequest_and_wait(coredev, msg,
498 msg->msgLength,
499 &coredev->reload_start_done);
500 mem_address = *(u32 *) &payload[20];
503 while (size && rc >= 0) {
504 struct SmsDataDownload_ST *DataMsg =
505 (struct SmsDataDownload_ST *) msg;
506 int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
508 SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
509 (u16)(sizeof(struct SmsMsgHdr_ST) +
510 sizeof(u32) + payload_size));
512 DataMsg->MemAddr = mem_address;
513 memcpy(DataMsg->Payload, payload, payload_size);
515 if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
516 (coredev->mode == DEVICE_MODE_NONE))
517 rc = coredev->sendrequest_handler(
518 coredev->context, DataMsg,
519 DataMsg->xMsgHeader.msgLength);
520 else
521 rc = smscore_sendrequest_and_wait(
522 coredev, DataMsg,
523 DataMsg->xMsgHeader.msgLength,
524 &coredev->data_download_done);
526 payload += payload_size;
527 size -= payload_size;
528 mem_address += payload_size;
531 if (rc >= 0) {
532 if (coredev->mode == DEVICE_MODE_NONE) {
533 struct SmsMsgData_ST *TriggerMsg =
534 (struct SmsMsgData_ST *) msg;
536 SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
537 sizeof(struct SmsMsgHdr_ST) +
538 sizeof(u32) * 5);
540 TriggerMsg->msgData[0] = firmware->StartAddress;
541 /* Entry point */
542 TriggerMsg->msgData[1] = 5; /* Priority */
543 TriggerMsg->msgData[2] = 0x200; /* Stack size */
544 TriggerMsg->msgData[3] = 0; /* Parameter */
545 TriggerMsg->msgData[4] = 4; /* Task ID */
547 if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
548 rc = coredev->sendrequest_handler(
549 coredev->context, TriggerMsg,
550 TriggerMsg->xMsgHeader.msgLength);
551 msleep(100);
552 } else
553 rc = smscore_sendrequest_and_wait(
554 coredev, TriggerMsg,
555 TriggerMsg->xMsgHeader.msgLength,
556 &coredev->trigger_done);
557 } else {
558 SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
559 sizeof(struct SmsMsgHdr_ST));
561 rc = coredev->sendrequest_handler(coredev->context,
562 msg, msg->msgLength);
564 msleep(500);
567 sms_debug("rc=%d, postload=%p ", rc,
568 coredev->postload_handler);
570 kfree(msg);
572 return ((rc >= 0) && coredev->postload_handler) ?
573 coredev->postload_handler(coredev->context) :
578 * loads specified firmware into a buffer and calls device loadfirmware_handler
580 * @param coredev pointer to a coredev object returned by
581 * smscore_register_device
582 * @param filename null-terminated string specifies firmware file name
583 * @param loadfirmware_handler device handler that loads firmware
585 * @return 0 on success, <0 on error.
587 static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
588 char *filename,
589 loadfirmware_t loadfirmware_handler)
591 int rc = -ENOENT;
592 const struct firmware *fw;
593 u8 *fw_buffer;
595 if (loadfirmware_handler == NULL && !(coredev->device_flags &
596 SMS_DEVICE_FAMILY2))
597 return -EINVAL;
599 rc = request_firmware(&fw, filename, coredev->device);
600 if (rc < 0) {
601 sms_info("failed to open \"%s\"", filename);
602 return rc;
604 sms_info("read FW %s, size=%zd", filename, fw->size);
605 fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
606 GFP_KERNEL | GFP_DMA);
607 if (fw_buffer) {
608 memcpy(fw_buffer, fw->data, fw->size);
610 rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
611 smscore_load_firmware_family2(coredev,
612 fw_buffer,
613 fw->size) :
614 loadfirmware_handler(coredev->context,
615 fw_buffer, fw->size);
617 kfree(fw_buffer);
618 } else {
619 sms_info("failed to allocate firmware buffer");
620 rc = -ENOMEM;
623 release_firmware(fw);
625 return rc;
629 * notifies all clients registered with the device, notifies hotplugs,
630 * frees all buffers and coredev object
632 * @param coredev pointer to a coredev object returned by
633 * smscore_register_device
635 * @return 0 on success, <0 on error.
637 void smscore_unregister_device(struct smscore_device_t *coredev)
639 struct smscore_buffer_t *cb;
640 int num_buffers = 0;
641 int retry = 0;
643 kmutex_lock(&g_smscore_deviceslock);
645 smscore_notify_clients(coredev);
646 smscore_notify_callbacks(coredev, NULL, 0);
648 /* at this point all buffers should be back
649 * onresponse must no longer be called */
651 while (1) {
652 while ((cb = smscore_getbuffer(coredev))) {
653 kfree(cb);
654 num_buffers++;
656 if (num_buffers == coredev->num_buffers)
657 break;
658 if (++retry > 10) {
659 sms_info("exiting although "
660 "not all buffers released.");
661 break;
664 sms_info("waiting for %d buffer(s)",
665 coredev->num_buffers - num_buffers);
666 msleep(100);
669 sms_info("freed %d buffers", num_buffers);
671 if (coredev->common_buffer)
672 dma_free_coherent(NULL, coredev->common_buffer_size,
673 coredev->common_buffer,
674 coredev->common_buffer_phys);
676 list_del(&coredev->entry);
677 kfree(coredev);
679 kmutex_unlock(&g_smscore_deviceslock);
681 sms_info("device %p destroyed", coredev);
684 static int smscore_detect_mode(struct smscore_device_t *coredev)
686 void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
687 GFP_KERNEL | GFP_DMA);
688 struct SmsMsgHdr_ST *msg =
689 (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
690 int rc;
692 if (!buffer)
693 return -ENOMEM;
695 SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
696 sizeof(struct SmsMsgHdr_ST));
698 rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
699 &coredev->version_ex_done);
700 if (rc == -ETIME) {
701 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
703 if (wait_for_completion_timeout(&coredev->resume_done,
704 msecs_to_jiffies(5000))) {
705 rc = smscore_sendrequest_and_wait(
706 coredev, msg, msg->msgLength,
707 &coredev->version_ex_done);
708 if (rc < 0)
709 sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
710 "second try, rc %d", rc);
711 } else
712 rc = -ETIME;
715 kfree(buffer);
717 return rc;
720 static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
721 /*Stellar NOVA A0 Nova B0 VEGA*/
722 /*DVBT*/
723 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
724 /*DVBH*/
725 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
726 /*TDMB*/
727 {"none", "tdmb_nova_12mhz.inp", "none", "none"},
728 /*DABIP*/
729 {"none", "none", "none", "none"},
730 /*BDA*/
731 {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
732 /*ISDBT*/
733 {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
734 /*ISDBTBDA*/
735 {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
736 /*CMMB*/
737 {"none", "none", "none", "cmmb_vega_12mhz.inp"}
740 static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
741 int mode, enum sms_device_type_st type)
743 char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
744 return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
748 * calls device handler to change mode of operation
749 * NOTE: stellar/usb may disconnect when changing mode
751 * @param coredev pointer to a coredev object returned by
752 * smscore_register_device
753 * @param mode requested mode of operation
755 * @return 0 on success, <0 on error.
757 int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
759 void *buffer;
760 int rc = 0;
761 enum sms_device_type_st type;
763 sms_debug("set device mode to %d", mode);
764 if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
765 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
766 sms_err("invalid mode specified %d", mode);
767 return -EINVAL;
770 smscore_registry_setmode(coredev->devpath, mode);
772 if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
773 rc = smscore_detect_mode(coredev);
774 if (rc < 0) {
775 sms_err("mode detect failed %d", rc);
776 return rc;
780 if (coredev->mode == mode) {
781 sms_info("device mode %d already set", mode);
782 return 0;
785 if (!(coredev->modes_supported & (1 << mode))) {
786 char *fw_filename;
788 type = smscore_registry_gettype(coredev->devpath);
789 fw_filename = sms_get_fw_name(coredev, mode, type);
791 rc = smscore_load_firmware_from_file(coredev,
792 fw_filename, NULL);
793 if (rc < 0) {
794 sms_warn("error %d loading firmware: %s, "
795 "trying again with default firmware",
796 rc, fw_filename);
798 /* try again with the default firmware */
799 fw_filename = smscore_fw_lkup[mode][type];
800 rc = smscore_load_firmware_from_file(coredev,
801 fw_filename, NULL);
803 if (rc < 0) {
804 sms_warn("error %d loading "
805 "firmware: %s", rc,
806 fw_filename);
807 return rc;
810 sms_log("firmware download success: %s", fw_filename);
811 } else
812 sms_info("mode %d supported by running "
813 "firmware", mode);
815 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
816 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
817 if (buffer) {
818 struct SmsMsgData_ST *msg =
819 (struct SmsMsgData_ST *)
820 SMS_ALIGN_ADDRESS(buffer);
822 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
823 sizeof(struct SmsMsgData_ST));
824 msg->msgData[0] = mode;
826 rc = smscore_sendrequest_and_wait(
827 coredev, msg, msg->xMsgHeader.msgLength,
828 &coredev->init_device_done);
830 kfree(buffer);
831 } else {
832 sms_err("Could not allocate buffer for "
833 "init device message.");
834 rc = -ENOMEM;
836 } else {
837 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
838 sms_err("invalid mode specified %d", mode);
839 return -EINVAL;
842 smscore_registry_setmode(coredev->devpath, mode);
844 if (coredev->detectmode_handler)
845 coredev->detectmode_handler(coredev->context,
846 &coredev->mode);
848 if (coredev->mode != mode && coredev->setmode_handler)
849 rc = coredev->setmode_handler(coredev->context, mode);
852 if (rc >= 0) {
853 coredev->mode = mode;
854 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
857 if (rc != 0)
858 sms_err("return error code %d.", rc);
859 return rc;
863 * calls device handler to get current mode of operation
865 * @param coredev pointer to a coredev object returned by
866 * smscore_register_device
868 * @return current mode
870 int smscore_get_device_mode(struct smscore_device_t *coredev)
872 return coredev->mode;
876 * find client by response id & type within the clients list.
877 * return client handle or NULL.
879 * @param coredev pointer to a coredev object returned by
880 * smscore_register_device
881 * @param data_type client data type (SMS_DONT_CARE for all types)
882 * @param id client id (SMS_DONT_CARE for all id)
885 static struct
886 smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
887 int data_type, int id)
889 struct smscore_client_t *client = NULL;
890 struct list_head *next, *first;
891 unsigned long flags;
892 struct list_head *firstid, *nextid;
895 spin_lock_irqsave(&coredev->clientslock, flags);
896 first = &coredev->clients;
897 for (next = first->next;
898 (next != first) && !client;
899 next = next->next) {
900 firstid = &((struct smscore_client_t *)next)->idlist;
901 for (nextid = firstid->next;
902 nextid != firstid;
903 nextid = nextid->next) {
904 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
905 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
906 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
907 client = (struct smscore_client_t *) next;
908 break;
912 spin_unlock_irqrestore(&coredev->clientslock, flags);
913 return client;
917 * find client by response id/type, call clients onresponse handler
918 * return buffer to pool on error
920 * @param coredev pointer to a coredev object returned by
921 * smscore_register_device
922 * @param cb pointer to response buffer descriptor
925 void smscore_onresponse(struct smscore_device_t *coredev,
926 struct smscore_buffer_t *cb)
928 struct SmsMsgHdr_ST *phdr =
929 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
930 struct smscore_client_t *client =
931 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
932 int rc = -EBUSY;
934 static unsigned long last_sample_time; /* = 0; */
935 static int data_total; /* = 0; */
936 unsigned long time_now = jiffies_to_msecs(jiffies);
938 if (!last_sample_time)
939 last_sample_time = time_now;
941 if (time_now - last_sample_time > 10000) {
942 sms_debug("\ndata rate %d bytes/secs",
943 (int)((data_total * 1000) /
944 (time_now - last_sample_time)));
946 last_sample_time = time_now;
947 data_total = 0;
950 data_total += cb->size;
951 /* If no client registered for type & id,
952 * check for control client where type is not registered */
953 if (client)
954 rc = client->onresponse_handler(client->context, cb);
956 if (rc < 0) {
957 switch (phdr->msgType) {
958 case MSG_SMS_GET_VERSION_EX_RES:
960 struct SmsVersionRes_ST *ver =
961 (struct SmsVersionRes_ST *) phdr;
962 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
963 "id %d prots 0x%x ver %d.%d",
964 ver->FirmwareId, ver->SupportedProtocols,
965 ver->RomVersionMajor, ver->RomVersionMinor);
967 coredev->mode = ver->FirmwareId == 255 ?
968 DEVICE_MODE_NONE : ver->FirmwareId;
969 coredev->modes_supported = ver->SupportedProtocols;
971 complete(&coredev->version_ex_done);
972 break;
974 case MSG_SMS_INIT_DEVICE_RES:
975 sms_debug("MSG_SMS_INIT_DEVICE_RES");
976 complete(&coredev->init_device_done);
977 break;
978 case MSG_SW_RELOAD_START_RES:
979 sms_debug("MSG_SW_RELOAD_START_RES");
980 complete(&coredev->reload_start_done);
981 break;
982 case MSG_SMS_DATA_DOWNLOAD_RES:
983 complete(&coredev->data_download_done);
984 break;
985 case MSG_SW_RELOAD_EXEC_RES:
986 sms_debug("MSG_SW_RELOAD_EXEC_RES");
987 break;
988 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
989 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
990 complete(&coredev->trigger_done);
991 break;
992 case MSG_SMS_SLEEP_RESUME_COMP_IND:
993 complete(&coredev->resume_done);
994 break;
995 default:
996 break;
998 smscore_putbuffer(coredev, cb);
1003 * return pointer to next free buffer descriptor from core pool
1005 * @param coredev pointer to a coredev object returned by
1006 * smscore_register_device
1008 * @return pointer to descriptor on success, NULL on error.
1010 struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1012 struct smscore_buffer_t *cb = NULL;
1013 unsigned long flags;
1015 spin_lock_irqsave(&coredev->bufferslock, flags);
1017 if (!list_empty(&coredev->buffers)) {
1018 cb = (struct smscore_buffer_t *) coredev->buffers.next;
1019 list_del(&cb->entry);
1022 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1024 return cb;
1028 * return buffer descriptor to a pool
1030 * @param coredev pointer to a coredev object returned by
1031 * smscore_register_device
1032 * @param cb pointer buffer descriptor
1035 void smscore_putbuffer(struct smscore_device_t *coredev,
1036 struct smscore_buffer_t *cb)
1038 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1041 static int smscore_validate_client(struct smscore_device_t *coredev,
1042 struct smscore_client_t *client,
1043 int data_type, int id)
1045 struct smscore_idlist_t *listentry;
1046 struct smscore_client_t *registered_client;
1048 if (!client) {
1049 sms_err("bad parameter.");
1050 return -EFAULT;
1052 registered_client = smscore_find_client(coredev, data_type, id);
1053 if (registered_client == client)
1054 return 0;
1056 if (registered_client) {
1057 sms_err("The msg ID already registered to another client.");
1058 return -EEXIST;
1060 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1061 if (!listentry) {
1062 sms_err("Can't allocate memory for client id.");
1063 return -ENOMEM;
1065 listentry->id = id;
1066 listentry->data_type = data_type;
1067 list_add_locked(&listentry->entry, &client->idlist,
1068 &coredev->clientslock);
1069 return 0;
1073 * creates smsclient object, check that id is taken by another client
1075 * @param coredev pointer to a coredev object from clients hotplug
1076 * @param initial_id all messages with this id would be sent to this client
1077 * @param data_type all messages of this type would be sent to this client
1078 * @param onresponse_handler client handler that is called to
1079 * process incoming messages
1080 * @param onremove_handler client handler that is called when device is removed
1081 * @param context client-specific context
1082 * @param client pointer to a value that receives created smsclient object
1084 * @return 0 on success, <0 on error.
1086 int smscore_register_client(struct smscore_device_t *coredev,
1087 struct smsclient_params_t *params,
1088 struct smscore_client_t **client)
1090 struct smscore_client_t *newclient;
1091 /* check that no other channel with same parameters exists */
1092 if (smscore_find_client(coredev, params->data_type,
1093 params->initial_id)) {
1094 sms_err("Client already exist.");
1095 return -EEXIST;
1098 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1099 if (!newclient) {
1100 sms_err("Failed to allocate memory for client.");
1101 return -ENOMEM;
1104 INIT_LIST_HEAD(&newclient->idlist);
1105 newclient->coredev = coredev;
1106 newclient->onresponse_handler = params->onresponse_handler;
1107 newclient->onremove_handler = params->onremove_handler;
1108 newclient->context = params->context;
1109 list_add_locked(&newclient->entry, &coredev->clients,
1110 &coredev->clientslock);
1111 smscore_validate_client(coredev, newclient, params->data_type,
1112 params->initial_id);
1113 *client = newclient;
1114 sms_debug("%p %d %d", params->context, params->data_type,
1115 params->initial_id);
1117 return 0;
1121 * frees smsclient object and all subclients associated with it
1123 * @param client pointer to smsclient object returned by
1124 * smscore_register_client
1127 void smscore_unregister_client(struct smscore_client_t *client)
1129 struct smscore_device_t *coredev = client->coredev;
1130 unsigned long flags;
1132 spin_lock_irqsave(&coredev->clientslock, flags);
1135 while (!list_empty(&client->idlist)) {
1136 struct smscore_idlist_t *identry =
1137 (struct smscore_idlist_t *) client->idlist.next;
1138 list_del(&identry->entry);
1139 kfree(identry);
1142 sms_info("%p", client->context);
1144 list_del(&client->entry);
1145 kfree(client);
1147 spin_unlock_irqrestore(&coredev->clientslock, flags);
1151 * verifies that source id is not taken by another client,
1152 * calls device handler to send requests to the device
1154 * @param client pointer to smsclient object returned by
1155 * smscore_register_client
1156 * @param buffer pointer to a request buffer
1157 * @param size size (in bytes) of request buffer
1159 * @return 0 on success, <0 on error.
1161 int smsclient_sendrequest(struct smscore_client_t *client,
1162 void *buffer, size_t size)
1164 struct smscore_device_t *coredev;
1165 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1166 int rc;
1168 if (client == NULL) {
1169 sms_err("Got NULL client");
1170 return -EINVAL;
1173 coredev = client->coredev;
1175 /* check that no other channel with same id exists */
1176 if (coredev == NULL) {
1177 sms_err("Got NULL coredev");
1178 return -EINVAL;
1181 rc = smscore_validate_client(client->coredev, client, 0,
1182 phdr->msgSrcId);
1183 if (rc < 0)
1184 return rc;
1186 return coredev->sendrequest_handler(coredev->context, buffer, size);
1190 static int __init smscore_module_init(void)
1192 int rc = 0;
1194 INIT_LIST_HEAD(&g_smscore_notifyees);
1195 INIT_LIST_HEAD(&g_smscore_devices);
1196 kmutex_init(&g_smscore_deviceslock);
1198 INIT_LIST_HEAD(&g_smscore_registry);
1199 kmutex_init(&g_smscore_registrylock);
1201 /* USB Register */
1202 rc = smsusb_register();
1204 /* DVB Register */
1205 rc = smsdvb_register();
1207 sms_debug("rc %d", rc);
1209 return rc;
1212 static void __exit smscore_module_exit(void)
1215 kmutex_lock(&g_smscore_deviceslock);
1216 while (!list_empty(&g_smscore_notifyees)) {
1217 struct smscore_device_notifyee_t *notifyee =
1218 (struct smscore_device_notifyee_t *)
1219 g_smscore_notifyees.next;
1221 list_del(&notifyee->entry);
1222 kfree(notifyee);
1224 kmutex_unlock(&g_smscore_deviceslock);
1226 kmutex_lock(&g_smscore_registrylock);
1227 while (!list_empty(&g_smscore_registry)) {
1228 struct smscore_registry_entry_t *entry =
1229 (struct smscore_registry_entry_t *)
1230 g_smscore_registry.next;
1232 list_del(&entry->entry);
1233 kfree(entry);
1235 kmutex_unlock(&g_smscore_registrylock);
1237 /* DVB UnRegister */
1238 smsdvb_unregister();
1240 /* Unregister USB */
1241 smsusb_unregister();
1243 sms_debug("");
1246 module_init(smscore_module_init);
1247 module_exit(smscore_module_exit);
1249 MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
1250 MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
1251 MODULE_LICENSE("GPL");