linux/drivers/media/dvb/siano/smscoreapi.c
<<
>>
Prefs
   1/*
   2 *  Siano core API module
   3 *
   4 *  This file contains implementation for the interface to sms core component
   5 *
   6 *  author: Uri Shkolnik
   7 *
   8 *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
   9 *
  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;
  13 *
  14 *  Software distributed under the License is distributed on an "AS IS"
  15 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
  16 *
  17 *  See the GNU General Public License for more details.
  18 *
  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.
  22 */
  23
  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>
  31
  32#include <linux/firmware.h>
  33#include <linux/wait.h>
  34#include <asm/byteorder.h>
  35
  36#include "smscoreapi.h"
  37#include "sms-cards.h"
  38#include "smsir.h"
  39#include "smsendian.h"
  40
  41static int sms_dbg;
  42module_param_named(debug, sms_dbg, int, 0644);
  43MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
  44
  45struct smscore_device_notifyee_t {
  46        struct list_head entry;
  47        hotplug_t hotplug;
  48};
  49
  50struct smscore_idlist_t {
  51        struct list_head entry;
  52        int             id;
  53        int             data_type;
  54};
  55
  56struct smscore_client_t {
  57        struct list_head entry;
  58        struct smscore_device_t *coredev;
  59        void                    *context;
  60        struct list_head        idlist;
  61        onresponse_t    onresponse_handler;
  62        onremove_t              onremove_handler;
  63};
  64
  65void smscore_set_board_id(struct smscore_device_t *core, int id)
  66{
  67        core->board_id = id;
  68}
  69
  70int smscore_led_state(struct smscore_device_t *core, int led)
  71{
  72        if (led >= 0)
  73                core->led_state = led;
  74        return core->led_state;
  75}
  76EXPORT_SYMBOL_GPL(smscore_set_board_id);
  77
  78int smscore_get_board_id(struct smscore_device_t *core)
  79{
  80        return core->board_id;
  81}
  82EXPORT_SYMBOL_GPL(smscore_get_board_id);
  83
  84struct smscore_registry_entry_t {
  85        struct list_head entry;
  86        char                    devpath[32];
  87        int                             mode;
  88        enum sms_device_type_st type;
  89};
  90
  91static struct list_head g_smscore_notifyees;
  92static struct list_head g_smscore_devices;
  93static struct mutex g_smscore_deviceslock;
  94
  95static struct list_head g_smscore_registry;
  96static struct mutex g_smscore_registrylock;
  97
  98static int default_mode = 4;
  99
 100module_param(default_mode, int, 0644);
 101MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
 102
 103static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
 104{
 105        struct smscore_registry_entry_t *entry;
 106        struct list_head *next;
 107
 108        kmutex_lock(&g_smscore_registrylock);
 109        for (next = g_smscore_registry.next;
 110             next != &g_smscore_registry;
 111             next = next->next) {
 112                entry = (struct smscore_registry_entry_t *) next;
 113                if (!strcmp(entry->devpath, devpath)) {
 114                        kmutex_unlock(&g_smscore_registrylock);
 115                        return entry;
 116                }
 117        }
 118        entry = (struct smscore_registry_entry_t *)
 119                        kmalloc(sizeof(struct smscore_registry_entry_t),
 120                                GFP_KERNEL);
 121        if (entry) {
 122                entry->mode = default_mode;
 123                strcpy(entry->devpath, devpath);
 124                list_add(&entry->entry, &g_smscore_registry);
 125        } else
 126                sms_err("failed to create smscore_registry.");
 127        kmutex_unlock(&g_smscore_registrylock);
 128        return entry;
 129}
 130
 131int smscore_registry_getmode(char *devpath)
 132{
 133        struct smscore_registry_entry_t *entry;
 134
 135        entry = smscore_find_registry(devpath);
 136        if (entry)
 137                return entry->mode;
 138        else
 139                sms_err("No registry found.");
 140
 141        return default_mode;
 142}
 143EXPORT_SYMBOL_GPL(smscore_registry_getmode);
 144
 145static enum sms_device_type_st smscore_registry_gettype(char *devpath)
 146{
 147        struct smscore_registry_entry_t *entry;
 148
 149        entry = smscore_find_registry(devpath);
 150        if (entry)
 151                return entry->type;
 152        else
 153                sms_err("No registry found.");
 154
 155        return -1;
 156}
 157
 158void smscore_registry_setmode(char *devpath, int mode)
 159{
 160        struct smscore_registry_entry_t *entry;
 161
 162        entry = smscore_find_registry(devpath);
 163        if (entry)
 164                entry->mode = mode;
 165        else
 166                sms_err("No registry found.");
 167}
 168
 169static void smscore_registry_settype(char *devpath,
 170                                     enum sms_device_type_st type)
 171{
 172        struct smscore_registry_entry_t *entry;
 173
 174        entry = smscore_find_registry(devpath);
 175        if (entry)
 176                entry->type = type;
 177        else
 178                sms_err("No registry found.");
 179}
 180
 181
 182static void list_add_locked(struct list_head *new, struct list_head *head,
 183                            spinlock_t *lock)
 184{
 185        unsigned long flags;
 186
 187        spin_lock_irqsave(lock, flags);
 188
 189        list_add(new, head);
 190
 191        spin_unlock_irqrestore(lock, flags);
 192}
 193
 194/**
 195 * register a client callback that called when device plugged in/unplugged
 196 * NOTE: if devices exist callback is called immediately for each device
 197 *
 198 * @param hotplug callback
 199 *
 200 * @return 0 on success, <0 on error.
 201 */
 202int smscore_register_hotplug(hotplug_t hotplug)
 203{
 204        struct smscore_device_notifyee_t *notifyee;
 205        struct list_head *next, *first;
 206        int rc = 0;
 207
 208        kmutex_lock(&g_smscore_deviceslock);
 209
 210        notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
 211                           GFP_KERNEL);
 212        if (notifyee) {
 213                /* now notify callback about existing devices */
 214                first = &g_smscore_devices;
 215                for (next = first->next;
 216                     next != first && !rc;
 217                     next = next->next) {
 218                        struct smscore_device_t *coredev =
 219                                (struct smscore_device_t *) next;
 220                        rc = hotplug(coredev, coredev->device, 1);
 221                }
 222
 223                if (rc >= 0) {
 224                        notifyee->hotplug = hotplug;
 225                        list_add(&notifyee->entry, &g_smscore_notifyees);
 226                } else
 227                        kfree(notifyee);
 228        } else
 229                rc = -ENOMEM;
 230
 231        kmutex_unlock(&g_smscore_deviceslock);
 232
 233        return rc;
 234}
 235EXPORT_SYMBOL_GPL(smscore_register_hotplug);
 236
 237/**
 238 * unregister a client callback that called when device plugged in/unplugged
 239 *
 240 * @param hotplug callback
 241 *
 242 */
 243void smscore_unregister_hotplug(hotplug_t hotplug)
 244{
 245        struct list_head *next, *first;
 246
 247        kmutex_lock(&g_smscore_deviceslock);
 248
 249        first = &g_smscore_notifyees;
 250
 251        for (next = first->next; next != first;) {
 252                struct smscore_device_notifyee_t *notifyee =
 253                        (struct smscore_device_notifyee_t *) next;
 254                next = next->next;
 255
 256                if (notifyee->hotplug == hotplug) {
 257                        list_del(&notifyee->entry);
 258                        kfree(notifyee);
 259                }
 260        }
 261
 262        kmutex_unlock(&g_smscore_deviceslock);
 263}
 264EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
 265
 266static void smscore_notify_clients(struct smscore_device_t *coredev)
 267{
 268        struct smscore_client_t *client;
 269
 270        /* the client must call smscore_unregister_client from remove handler */
 271        while (!list_empty(&coredev->clients)) {
 272                client = (struct smscore_client_t *) coredev->clients.next;
 273                client->onremove_handler(client->context);
 274        }
 275}
 276
 277static int smscore_notify_callbacks(struct smscore_device_t *coredev,
 278                                    struct device *device, int arrival)
 279{
 280        struct list_head *next, *first;
 281        int rc = 0;
 282
 283        /* note: must be called under g_deviceslock */
 284
 285        first = &g_smscore_notifyees;
 286
 287        for (next = first->next; next != first; next = next->next) {
 288                rc = ((struct smscore_device_notifyee_t *) next)->
 289                                hotplug(coredev, device, arrival);
 290                if (rc < 0)
 291                        break;
 292        }
 293
 294        return rc;
 295}
 296
 297static struct
 298smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
 299                                       dma_addr_t common_buffer_phys)
 300{
 301        struct smscore_buffer_t *cb =
 302                kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
 303        if (!cb) {
 304                sms_info("kmalloc(...) failed");
 305                return NULL;
 306        }
 307
 308        cb->p = buffer;
 309        cb->offset_in_common = buffer - (u8 *) common_buffer;
 310        cb->phys = common_buffer_phys + cb->offset_in_common;
 311
 312        return cb;
 313}
 314
 315/**
 316 * creates coredev object for a device, prepares buffers,
 317 * creates buffer mappings, notifies registered hotplugs about new device.
 318 *
 319 * @param params device pointer to struct with device specific parameters
 320 *               and handlers
 321 * @param coredev pointer to a value that receives created coredev object
 322 *
 323 * @return 0 on success, <0 on error.
 324 */
 325int smscore_register_device(struct smsdevice_params_t *params,
 326                            struct smscore_device_t **coredev)
 327{
 328        struct smscore_device_t *dev;
 329        u8 *buffer;
 330
 331        dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
 332        if (!dev) {
 333                sms_info("kzalloc(...) failed");
 334                return -ENOMEM;
 335        }
 336
 337        /* init list entry so it could be safe in smscore_unregister_device */
 338        INIT_LIST_HEAD(&dev->entry);
 339
 340        /* init queues */
 341        INIT_LIST_HEAD(&dev->clients);
 342        INIT_LIST_HEAD(&dev->buffers);
 343
 344        /* init locks */
 345        spin_lock_init(&dev->clientslock);
 346        spin_lock_init(&dev->bufferslock);
 347
 348        /* init completion events */
 349        init_completion(&dev->version_ex_done);
 350        init_completion(&dev->data_download_done);
 351        init_completion(&dev->trigger_done);
 352        init_completion(&dev->init_device_done);
 353        init_completion(&dev->reload_start_done);
 354        init_completion(&dev->resume_done);
 355        init_completion(&dev->gpio_configuration_done);
 356        init_completion(&dev->gpio_set_level_done);
 357        init_completion(&dev->gpio_get_level_done);
 358        init_completion(&dev->ir_init_done);
 359
 360        /* Buffer management */
 361        init_waitqueue_head(&dev->buffer_mng_waitq);
 362
 363        /* alloc common buffer */
 364        dev->common_buffer_size = params->buffer_size * params->num_buffers;
 365        dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
 366                                                &dev->common_buffer_phys,
 367                                                GFP_KERNEL | GFP_DMA);
 368        if (!dev->common_buffer) {
 369                smscore_unregister_device(dev);
 370                return -ENOMEM;
 371        }
 372
 373        /* prepare dma buffers */
 374        for (buffer = dev->common_buffer;
 375             dev->num_buffers < params->num_buffers;
 376             dev->num_buffers++, buffer += params->buffer_size) {
 377                struct smscore_buffer_t *cb =
 378                        smscore_createbuffer(buffer, dev->common_buffer,
 379                                             dev->common_buffer_phys);
 380                if (!cb) {
 381                        smscore_unregister_device(dev);
 382                        return -ENOMEM;
 383                }
 384
 385                smscore_putbuffer(dev, cb);
 386        }
 387
 388        sms_info("allocated %d buffers", dev->num_buffers);
 389
 390        dev->mode = DEVICE_MODE_NONE;
 391        dev->context = params->context;
 392        dev->device = params->device;
 393        dev->setmode_handler = params->setmode_handler;
 394        dev->detectmode_handler = params->detectmode_handler;
 395        dev->sendrequest_handler = params->sendrequest_handler;
 396        dev->preload_handler = params->preload_handler;
 397        dev->postload_handler = params->postload_handler;
 398
 399        dev->device_flags = params->flags;
 400        strcpy(dev->devpath, params->devpath);
 401
 402        smscore_registry_settype(dev->devpath, params->device_type);
 403
 404        /* add device to devices list */
 405        kmutex_lock(&g_smscore_deviceslock);
 406        list_add(&dev->entry, &g_smscore_devices);
 407        kmutex_unlock(&g_smscore_deviceslock);
 408
 409        *coredev = dev;
 410
 411        sms_info("device %p created", dev);
 412
 413        return 0;
 414}
 415EXPORT_SYMBOL_GPL(smscore_register_device);
 416
 417
 418static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
 419                void *buffer, size_t size, struct completion *completion) {
 420        int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
 421        if (rc < 0) {
 422                sms_info("sendrequest returned error %d", rc);
 423                return rc;
 424        }
 425
 426        return wait_for_completion_timeout(completion,
 427                        msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
 428                        0 : -ETIME;
 429}
 430
 431/**
 432 * Starts & enables IR operations
 433 *
 434 * @return 0 on success, < 0 on error.
 435 */
 436static int smscore_init_ir(struct smscore_device_t *coredev)
 437{
 438        int ir_io;
 439        int rc;
 440        void *buffer;
 441
 442        coredev->ir.input_dev = NULL;
 443        ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
 444        if (ir_io) {/* only if IR port exist we use IR sub-module */
 445                sms_info("IR loading");
 446                rc = sms_ir_init(coredev);
 447
 448                if      (rc != 0)
 449                        sms_err("Error initialization DTV IR sub-module");
 450                else {
 451                        buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
 452                                                SMS_DMA_ALIGNMENT,
 453                                                GFP_KERNEL | GFP_DMA);
 454                        if (buffer) {
 455                                struct SmsMsgData_ST2 *msg =
 456                                (struct SmsMsgData_ST2 *)
 457                                SMS_ALIGN_ADDRESS(buffer);
 458
 459                                SMS_INIT_MSG(&msg->xMsgHeader,
 460                                                MSG_SMS_START_IR_REQ,
 461                                                sizeof(struct SmsMsgData_ST2));
 462                                msg->msgData[0] = coredev->ir.controller;
 463                                msg->msgData[1] = coredev->ir.timeout;
 464
 465                                smsendian_handle_tx_message(
 466                                        (struct SmsMsgHdr_ST2 *)msg);
 467                                rc = smscore_sendrequest_and_wait(coredev, msg,
 468                                                msg->xMsgHeader. msgLength,
 469                                                &coredev->ir_init_done);
 470
 471                                kfree(buffer);
 472                        } else
 473                                sms_err
 474                                ("Sending IR initialization message failed");
 475                }
 476        } else
 477                sms_info("IR port has not been detected");
 478
 479        return 0;
 480}
 481
 482/**
 483 * sets initial device mode and notifies client hotplugs that device is ready
 484 *
 485 * @param coredev pointer to a coredev object returned by
 486 *                smscore_register_device
 487 *
 488 * @return 0 on success, <0 on error.
 489 */
 490int smscore_start_device(struct smscore_device_t *coredev)
 491{
 492        int rc = smscore_set_device_mode(
 493                        coredev, smscore_registry_getmode(coredev->devpath));
 494        if (rc < 0) {
 495                sms_info("set device mode faile , rc %d", rc);
 496                return rc;
 497        }
 498
 499        kmutex_lock(&g_smscore_deviceslock);
 500
 501        rc = smscore_notify_callbacks(coredev, coredev->device, 1);
 502        smscore_init_ir(coredev);
 503
 504        sms_info("device %p started, rc %d", coredev, rc);
 505
 506        kmutex_unlock(&g_smscore_deviceslock);
 507
 508        return rc;
 509}
 510EXPORT_SYMBOL_GPL(smscore_start_device);
 511
 512
 513static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
 514                                         void *buffer, size_t size)
 515{
 516        struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
 517        struct SmsMsgHdr_ST *msg;
 518        u32 mem_address;
 519        u8 *payload = firmware->Payload;
 520        int rc = 0;
 521        firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
 522        firmware->Length = le32_to_cpu(firmware->Length);
 523
 524        mem_address = firmware->StartAddress;
 525
 526        sms_info("loading FW to addr 0x%x size %d",
 527                 mem_address, firmware->Length);
 528        if (coredev->preload_handler) {
 529                rc = coredev->preload_handler(coredev->context);
 530                if (rc < 0)
 531                        return rc;
 532        }
 533
 534        /* PAGE_SIZE buffer shall be enough and dma aligned */
 535        msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
 536        if (!msg)
 537                return -ENOMEM;
 538
 539        if (coredev->mode != DEVICE_MODE_NONE) {
 540                sms_debug("sending reload command.");
 541                SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
 542                             sizeof(struct SmsMsgHdr_ST));
 543                rc = smscore_sendrequest_and_wait(coredev, msg,
 544                                                  msg->msgLength,
 545                                                  &coredev->reload_start_done);
 546                mem_address = *(u32 *) &payload[20];
 547        }
 548
 549        while (size && rc >= 0) {
 550                struct SmsDataDownload_ST *DataMsg =
 551                        (struct SmsDataDownload_ST *) msg;
 552                int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
 553
 554                SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
 555                             (u16)(sizeof(struct SmsMsgHdr_ST) +
 556                                      sizeof(u32) + payload_size));
 557
 558                DataMsg->MemAddr = mem_address;
 559                memcpy(DataMsg->Payload, payload, payload_size);
 560
 561                if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
 562                    (coredev->mode == DEVICE_MODE_NONE))
 563                        rc = coredev->sendrequest_handler(
 564                                coredev->context, DataMsg,
 565                                DataMsg->xMsgHeader.msgLength);
 566                else
 567                        rc = smscore_sendrequest_and_wait(
 568                                coredev, DataMsg,
 569                                DataMsg->xMsgHeader.msgLength,
 570                                &coredev->data_download_done);
 571
 572                payload += payload_size;
 573                size -= payload_size;
 574                mem_address += payload_size;
 575        }
 576
 577        if (rc >= 0) {
 578                if (coredev->mode == DEVICE_MODE_NONE) {
 579                        struct SmsMsgData_ST *TriggerMsg =
 580                                (struct SmsMsgData_ST *) msg;
 581
 582                        SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
 583                                     sizeof(struct SmsMsgHdr_ST) +
 584                                     sizeof(u32) * 5);
 585
 586                        TriggerMsg->msgData[0] = firmware->StartAddress;
 587                                                /* Entry point */
 588                        TriggerMsg->msgData[1] = 5; /* Priority */
 589                        TriggerMsg->msgData[2] = 0x200; /* Stack size */
 590                        TriggerMsg->msgData[3] = 0; /* Parameter */
 591                        TriggerMsg->msgData[4] = 4; /* Task ID */
 592
 593                        if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
 594                                rc = coredev->sendrequest_handler(
 595                                        coredev->context, TriggerMsg,
 596                                        TriggerMsg->xMsgHeader.msgLength);
 597                                msleep(100);
 598                        } else
 599                                rc = smscore_sendrequest_and_wait(
 600                                        coredev, TriggerMsg,
 601                                        TriggerMsg->xMsgHeader.msgLength,
 602                                        &coredev->trigger_done);
 603                } else {
 604                        SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
 605                                     sizeof(struct SmsMsgHdr_ST));
 606
 607                        rc = coredev->sendrequest_handler(coredev->context,
 608                                                          msg, msg->msgLength);
 609                }
 610                msleep(500);
 611        }
 612
 613        sms_debug("rc=%d, postload=%p ", rc,
 614                  coredev->postload_handler);
 615
 616        kfree(msg);
 617
 618        return ((rc >= 0) && coredev->postload_handler) ?
 619                coredev->postload_handler(coredev->context) :
 620                rc;
 621}
 622
 623/**
 624 * loads specified firmware into a buffer and calls device loadfirmware_handler
 625 *
 626 * @param coredev pointer to a coredev object returned by
 627 *                smscore_register_device
 628 * @param filename null-terminated string specifies firmware file name
 629 * @param loadfirmware_handler device handler that loads firmware
 630 *
 631 * @return 0 on success, <0 on error.
 632 */
 633static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
 634                                           char *filename,
 635                                           loadfirmware_t loadfirmware_handler)
 636{
 637        int rc = -ENOENT;
 638        const struct firmware *fw;
 639        u8 *fw_buffer;
 640
 641        if (loadfirmware_handler == NULL && !(coredev->device_flags &
 642                                              SMS_DEVICE_FAMILY2))
 643                return -EINVAL;
 644
 645        rc = request_firmware(&fw, filename, coredev->device);
 646        if (rc < 0) {
 647                sms_info("failed to open \"%s\"", filename);
 648                return rc;
 649        }
 650        sms_info("read FW %s, size=%zd", filename, fw->size);
 651        fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
 652                            GFP_KERNEL | GFP_DMA);
 653        if (fw_buffer) {
 654                memcpy(fw_buffer, fw->data, fw->size);
 655
 656                rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
 657                      smscore_load_firmware_family2(coredev,
 658                                                    fw_buffer,
 659                                                    fw->size) :
 660                      loadfirmware_handler(coredev->context,
 661                                           fw_buffer, fw->size);
 662
 663                kfree(fw_buffer);
 664        } else {
 665                sms_info("failed to allocate firmware buffer");
 666                rc = -ENOMEM;
 667        }
 668
 669        release_firmware(fw);
 670
 671        return rc;
 672}
 673
 674/**
 675 * notifies all clients registered with the device, notifies hotplugs,
 676 * frees all buffers and coredev object
 677 *
 678 * @param coredev pointer to a coredev object returned by
 679 *                smscore_register_device
 680 *
 681 * @return 0 on success, <0 on error.
 682 */
 683void smscore_unregister_device(struct smscore_device_t *coredev)
 684{
 685        struct smscore_buffer_t *cb;
 686        int num_buffers = 0;
 687        int retry = 0;
 688
 689        kmutex_lock(&g_smscore_deviceslock);
 690
 691        /* Release input device (IR) resources */
 692        sms_ir_exit(coredev);
 693
 694        smscore_notify_clients(coredev);
 695        smscore_notify_callbacks(coredev, NULL, 0);
 696
 697        /* at this point all buffers should be back
 698         * onresponse must no longer be called */
 699
 700        while (1) {
 701                while (!list_empty(&coredev->buffers)) {
 702                        cb = (struct smscore_buffer_t *) coredev->buffers.next;
 703                        list_del(&cb->entry);
 704                        kfree(cb);
 705                        num_buffers++;
 706                }
 707                if (num_buffers == coredev->num_buffers)
 708                        break;
 709                if (++retry > 10) {
 710                        sms_info("exiting although "
 711                                 "not all buffers released.");
 712                        break;
 713                }
 714
 715                sms_info("waiting for %d buffer(s)",
 716                         coredev->num_buffers - num_buffers);
 717                msleep(100);
 718        }
 719
 720        sms_info("freed %d buffers", num_buffers);
 721
 722        if (coredev->common_buffer)
 723                dma_free_coherent(NULL, coredev->common_buffer_size,
 724                        coredev->common_buffer, coredev->common_buffer_phys);
 725
 726        if (coredev->fw_buf != NULL)
 727                kfree(coredev->fw_buf);
 728
 729        list_del(&coredev->entry);
 730        kfree(coredev);
 731
 732        kmutex_unlock(&g_smscore_deviceslock);
 733
 734        sms_info("device %p destroyed", coredev);
 735}
 736EXPORT_SYMBOL_GPL(smscore_unregister_device);
 737
 738static int smscore_detect_mode(struct smscore_device_t *coredev)
 739{
 740        void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
 741                               GFP_KERNEL | GFP_DMA);
 742        struct SmsMsgHdr_ST *msg =
 743                (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
 744        int rc;
 745
 746        if (!buffer)
 747                return -ENOMEM;
 748
 749        SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
 750                     sizeof(struct SmsMsgHdr_ST));
 751
 752        rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
 753                                          &coredev->version_ex_done);
 754        if (rc == -ETIME) {
 755                sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
 756
 757                if (wait_for_completion_timeout(&coredev->resume_done,
 758                                                msecs_to_jiffies(5000))) {
 759                        rc = smscore_sendrequest_and_wait(
 760                                coredev, msg, msg->msgLength,
 761                                &coredev->version_ex_done);
 762                        if (rc < 0)
 763                                sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
 764                                        "second try, rc %d", rc);
 765                } else
 766                        rc = -ETIME;
 767        }
 768
 769        kfree(buffer);
 770
 771        return rc;
 772}
 773
 774static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
 775        /*Stellar               NOVA A0         Nova B0         VEGA*/
 776        /*DVBT*/
 777        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
 778        /*DVBH*/
 779        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
 780        /*TDMB*/
 781        {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
 782        /*DABIP*/
 783        {"none", "none", "none", "none"},
 784        /*BDA*/
 785        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
 786        /*ISDBT*/
 787        {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
 788        /*ISDBTBDA*/
 789        {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
 790        /*CMMB*/
 791        {"none", "none", "none", "cmmb_vega_12mhz.inp"}
 792};
 793
 794static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
 795                                    int mode, enum sms_device_type_st type)
 796{
 797        char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
 798        return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
 799}
 800
 801/**
 802 * calls device handler to change mode of operation
 803 * NOTE: stellar/usb may disconnect when changing mode
 804 *
 805 * @param coredev pointer to a coredev object returned by
 806 *                smscore_register_device
 807 * @param mode requested mode of operation
 808 *
 809 * @return 0 on success, <0 on error.
 810 */
 811int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
 812{
 813        void *buffer;
 814        int rc = 0;
 815        enum sms_device_type_st type;
 816
 817        sms_debug("set device mode to %d", mode);
 818        if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
 819                if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
 820                        sms_err("invalid mode specified %d", mode);
 821                        return -EINVAL;
 822                }
 823
 824                smscore_registry_setmode(coredev->devpath, mode);
 825
 826                if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
 827                        rc = smscore_detect_mode(coredev);
 828                        if (rc < 0) {
 829                                sms_err("mode detect failed %d", rc);
 830                                return rc;
 831                        }
 832                }
 833
 834                if (coredev->mode == mode) {
 835                        sms_info("device mode %d already set", mode);
 836                        return 0;
 837                }
 838
 839                if (!(coredev->modes_supported & (1 << mode))) {
 840                        char *fw_filename;
 841
 842                        type = smscore_registry_gettype(coredev->devpath);
 843                        fw_filename = sms_get_fw_name(coredev, mode, type);
 844
 845                        rc = smscore_load_firmware_from_file(coredev,
 846                                                             fw_filename, NULL);
 847                        if (rc < 0) {
 848                                sms_warn("error %d loading firmware: %s, "
 849                                         "trying again with default firmware",
 850                                         rc, fw_filename);
 851
 852                                /* try again with the default firmware */
 853                                fw_filename = smscore_fw_lkup[mode][type];
 854                                rc = smscore_load_firmware_from_file(coredev,
 855                                                             fw_filename, NULL);
 856
 857                                if (rc < 0) {
 858                                        sms_warn("error %d loading "
 859                                                 "firmware: %s", rc,
 860                                                 fw_filename);
 861                                        return rc;
 862                                }
 863                        }
 864                        sms_log("firmware download success: %s", fw_filename);
 865                } else
 866                        sms_info("mode %d supported by running "
 867                                 "firmware", mode);
 868
 869                buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
 870                                 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
 871                if (buffer) {
 872                        struct SmsMsgData_ST *msg =
 873                                (struct SmsMsgData_ST *)
 874                                        SMS_ALIGN_ADDRESS(buffer);
 875
 876                        SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
 877                                     sizeof(struct SmsMsgData_ST));
 878                        msg->msgData[0] = mode;
 879
 880                        rc = smscore_sendrequest_and_wait(
 881                                coredev, msg, msg->xMsgHeader.msgLength,
 882                                &coredev->init_device_done);
 883
 884                        kfree(buffer);
 885                } else {
 886                        sms_err("Could not allocate buffer for "
 887                                "init device message.");
 888                        rc = -ENOMEM;
 889                }
 890        } else {
 891                if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
 892                        sms_err("invalid mode specified %d", mode);
 893                        return -EINVAL;
 894                }
 895
 896                smscore_registry_setmode(coredev->devpath, mode);
 897
 898                if (coredev->detectmode_handler)
 899                        coredev->detectmode_handler(coredev->context,
 900                                                    &coredev->mode);
 901
 902                if (coredev->mode != mode && coredev->setmode_handler)
 903                        rc = coredev->setmode_handler(coredev->context, mode);
 904        }
 905
 906        if (rc >= 0) {
 907                coredev->mode = mode;
 908                coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
 909        }
 910
 911        if (rc < 0)
 912                sms_err("return error code %d.", rc);
 913        return rc;
 914}
 915
 916/**
 917 * calls device handler to get current mode of operation
 918 *
 919 * @param coredev pointer to a coredev object returned by
 920 *                smscore_register_device
 921 *
 922 * @return current mode
 923 */
 924int smscore_get_device_mode(struct smscore_device_t *coredev)
 925{
 926        return coredev->mode;
 927}
 928EXPORT_SYMBOL_GPL(smscore_get_device_mode);
 929
 930/**
 931 * find client by response id & type within the clients list.
 932 * return client handle or NULL.
 933 *
 934 * @param coredev pointer to a coredev object returned by
 935 *                smscore_register_device
 936 * @param data_type client data type (SMS_DONT_CARE for all types)
 937 * @param id client id (SMS_DONT_CARE for all id)
 938 *
 939 */
 940static struct
 941smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
 942                                      int data_type, int id)
 943{
 944        struct smscore_client_t *client = NULL;
 945        struct list_head *next, *first;
 946        unsigned long flags;
 947        struct list_head *firstid, *nextid;
 948
 949
 950        spin_lock_irqsave(&coredev->clientslock, flags);
 951        first = &coredev->clients;
 952        for (next = first->next;
 953             (next != first) && !client;
 954             next = next->next) {
 955                firstid = &((struct smscore_client_t *)next)->idlist;
 956                for (nextid = firstid->next;
 957                     nextid != firstid;
 958                     nextid = nextid->next) {
 959                        if ((((struct smscore_idlist_t *)nextid)->id == id) &&
 960                            (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
 961                            (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
 962                                client = (struct smscore_client_t *) next;
 963                                break;
 964                        }
 965                }
 966        }
 967        spin_unlock_irqrestore(&coredev->clientslock, flags);
 968        return client;
 969}
 970
 971/**
 972 * find client by response id/type, call clients onresponse handler
 973 * return buffer to pool on error
 974 *
 975 * @param coredev pointer to a coredev object returned by
 976 *                smscore_register_device
 977 * @param cb pointer to response buffer descriptor
 978 *
 979 */
 980void smscore_onresponse(struct smscore_device_t *coredev,
 981                struct smscore_buffer_t *cb) {
 982        struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
 983                        + cb->offset);
 984        struct smscore_client_t *client;
 985        int rc = -EBUSY;
 986        static unsigned long last_sample_time; /* = 0; */
 987        static int data_total; /* = 0; */
 988        unsigned long time_now = jiffies_to_msecs(jiffies);
 989
 990        if (!last_sample_time)
 991                last_sample_time = time_now;
 992
 993        if (time_now - last_sample_time > 10000) {
 994                sms_debug("\ndata rate %d bytes/secs",
 995                          (int)((data_total * 1000) /
 996                                (time_now - last_sample_time)));
 997
 998                last_sample_time = time_now;
 999                data_total = 0;
1000        }
1001
1002        data_total += cb->size;
1003        /* Do we need to re-route? */
1004        if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
1005                        (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
1006                if (coredev->mode == DEVICE_MODE_DVBT_BDA)
1007                        phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
1008        }
1009
1010
1011        client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1012
1013        /* If no client registered for type & id,
1014         * check for control client where type is not registered */
1015        if (client)
1016                rc = client->onresponse_handler(client->context, cb);
1017
1018        if (rc < 0) {
1019                switch (phdr->msgType) {
1020                case MSG_SMS_GET_VERSION_EX_RES:
1021                {
1022                        struct SmsVersionRes_ST *ver =
1023                                (struct SmsVersionRes_ST *) phdr;
1024                        sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1025                                  "id %d prots 0x%x ver %d.%d",
1026                                  ver->FirmwareId, ver->SupportedProtocols,
1027                                  ver->RomVersionMajor, ver->RomVersionMinor);
1028
1029                        coredev->mode = ver->FirmwareId == 255 ?
1030                                DEVICE_MODE_NONE : ver->FirmwareId;
1031                        coredev->modes_supported = ver->SupportedProtocols;
1032
1033                        complete(&coredev->version_ex_done);
1034                        break;
1035                }
1036                case MSG_SMS_INIT_DEVICE_RES:
1037                        sms_debug("MSG_SMS_INIT_DEVICE_RES");
1038                        complete(&coredev->init_device_done);
1039                        break;
1040                case MSG_SW_RELOAD_START_RES:
1041                        sms_debug("MSG_SW_RELOAD_START_RES");
1042                        complete(&coredev->reload_start_done);
1043                        break;
1044                case MSG_SMS_DATA_DOWNLOAD_RES:
1045                        complete(&coredev->data_download_done);
1046                        break;
1047                case MSG_SW_RELOAD_EXEC_RES:
1048                        sms_debug("MSG_SW_RELOAD_EXEC_RES");
1049                        break;
1050                case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1051                        sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1052                        complete(&coredev->trigger_done);
1053                        break;
1054                case MSG_SMS_SLEEP_RESUME_COMP_IND:
1055                        complete(&coredev->resume_done);
1056                        break;
1057                case MSG_SMS_GPIO_CONFIG_EX_RES:
1058                        sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1059                        complete(&coredev->gpio_configuration_done);
1060                        break;
1061                case MSG_SMS_GPIO_SET_LEVEL_RES:
1062                        sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1063                        complete(&coredev->gpio_set_level_done);
1064                        break;
1065                case MSG_SMS_GPIO_GET_LEVEL_RES:
1066                {
1067                        u32 *msgdata = (u32 *) phdr;
1068                        coredev->gpio_get_res = msgdata[1];
1069                        sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1070                                        coredev->gpio_get_res);
1071                        complete(&coredev->gpio_get_level_done);
1072                        break;
1073                }
1074                case MSG_SMS_START_IR_RES:
1075                        complete(&coredev->ir_init_done);
1076                        break;
1077                case MSG_SMS_IR_SAMPLES_IND:
1078                        sms_ir_event(coredev,
1079                                (const char *)
1080                                ((char *)phdr
1081                                + sizeof(struct SmsMsgHdr_ST)),
1082                                (int)phdr->msgLength
1083                                - sizeof(struct SmsMsgHdr_ST));
1084                        break;
1085
1086                default:
1087                        break;
1088                }
1089                smscore_putbuffer(coredev, cb);
1090        }
1091}
1092EXPORT_SYMBOL_GPL(smscore_onresponse);
1093
1094/**
1095 * return pointer to next free buffer descriptor from core pool
1096 *
1097 * @param coredev pointer to a coredev object returned by
1098 *                smscore_register_device
1099 *
1100 * @return pointer to descriptor on success, NULL on error.
1101 */
1102struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1103{
1104        struct smscore_buffer_t *cb = NULL;
1105        unsigned long flags;
1106
1107        DEFINE_WAIT(wait);
1108
1109        spin_lock_irqsave(&coredev->bufferslock, flags);
1110
1111        /* This function must return a valid buffer, since the buffer list is
1112         * finite, we check that there is an available buffer, if not, we wait
1113         * until such buffer become available.
1114         */
1115
1116        prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
1117
1118        if (list_empty(&coredev->buffers))
1119                schedule();
1120
1121        finish_wait(&coredev->buffer_mng_waitq, &wait);
1122
1123        cb = (struct smscore_buffer_t *) coredev->buffers.next;
1124        list_del(&cb->entry);
1125
1126        spin_unlock_irqrestore(&coredev->bufferslock, flags);
1127
1128        return cb;
1129}
1130EXPORT_SYMBOL_GPL(smscore_getbuffer);
1131
1132/**
1133 * return buffer descriptor to a pool
1134 *
1135 * @param coredev pointer to a coredev object returned by
1136 *                smscore_register_device
1137 * @param cb pointer buffer descriptor
1138 *
1139 */
1140void smscore_putbuffer(struct smscore_device_t *coredev,
1141                struct smscore_buffer_t *cb) {
1142        wake_up_interruptible(&coredev->buffer_mng_waitq);
1143        list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1144}
1145EXPORT_SYMBOL_GPL(smscore_putbuffer);
1146
1147static int smscore_validate_client(struct smscore_device_t *coredev,
1148                                   struct smscore_client_t *client,
1149                                   int data_type, int id)
1150{
1151        struct smscore_idlist_t *listentry;
1152        struct smscore_client_t *registered_client;
1153
1154        if (!client) {
1155                sms_err("bad parameter.");
1156                return -EFAULT;
1157        }
1158        registered_client = smscore_find_client(coredev, data_type, id);
1159        if (registered_client == client)
1160                return 0;
1161
1162        if (registered_client) {
1163                sms_err("The msg ID already registered to another client.");
1164                return -EEXIST;
1165        }
1166        listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1167        if (!listentry) {
1168                sms_err("Can't allocate memory for client id.");
1169                return -ENOMEM;
1170        }
1171        listentry->id = id;
1172        listentry->data_type = data_type;
1173        list_add_locked(&listentry->entry, &client->idlist,
1174                        &coredev->clientslock);
1175        return 0;
1176}
1177
1178/**
1179 * creates smsclient object, check that id is taken by another client
1180 *
1181 * @param coredev pointer to a coredev object from clients hotplug
1182 * @param initial_id all messages with this id would be sent to this client
1183 * @param data_type all messages of this type would be sent to this client
1184 * @param onresponse_handler client handler that is called to
1185 *                           process incoming messages
1186 * @param onremove_handler client handler that is called when device is removed
1187 * @param context client-specific context
1188 * @param client pointer to a value that receives created smsclient object
1189 *
1190 * @return 0 on success, <0 on error.
1191 */
1192int smscore_register_client(struct smscore_device_t *coredev,
1193                            struct smsclient_params_t *params,
1194                            struct smscore_client_t **client)
1195{
1196        struct smscore_client_t *newclient;
1197        /* check that no other channel with same parameters exists */
1198        if (smscore_find_client(coredev, params->data_type,
1199                                params->initial_id)) {
1200                sms_err("Client already exist.");
1201                return -EEXIST;
1202        }
1203
1204        newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1205        if (!newclient) {
1206                sms_err("Failed to allocate memory for client.");
1207                return -ENOMEM;
1208        }
1209
1210        INIT_LIST_HEAD(&newclient->idlist);
1211        newclient->coredev = coredev;
1212        newclient->onresponse_handler = params->onresponse_handler;
1213        newclient->onremove_handler = params->onremove_handler;
1214        newclient->context = params->context;
1215        list_add_locked(&newclient->entry, &coredev->clients,
1216                        &coredev->clientslock);
1217        smscore_validate_client(coredev, newclient, params->data_type,
1218                                params->initial_id);
1219        *client = newclient;
1220        sms_debug("%p %d %d", params->context, params->data_type,
1221                  params->initial_id);
1222
1223        return 0;
1224}
1225EXPORT_SYMBOL_GPL(smscore_register_client);
1226
1227/**
1228 * frees smsclient object and all subclients associated with it
1229 *
1230 * @param client pointer to smsclient object returned by
1231 *               smscore_register_client
1232 *
1233 */
1234void smscore_unregister_client(struct smscore_client_t *client)
1235{
1236        struct smscore_device_t *coredev = client->coredev;
1237        unsigned long flags;
1238
1239        spin_lock_irqsave(&coredev->clientslock, flags);
1240
1241
1242        while (!list_empty(&client->idlist)) {
1243                struct smscore_idlist_t *identry =
1244                        (struct smscore_idlist_t *) client->idlist.next;
1245                list_del(&identry->entry);
1246                kfree(identry);
1247        }
1248
1249        sms_info("%p", client->context);
1250
1251        list_del(&client->entry);
1252        kfree(client);
1253
1254        spin_unlock_irqrestore(&coredev->clientslock, flags);
1255}
1256EXPORT_SYMBOL_GPL(smscore_unregister_client);
1257
1258/**
1259 * verifies that source id is not taken by another client,
1260 * calls device handler to send requests to the device
1261 *
1262 * @param client pointer to smsclient object returned by
1263 *               smscore_register_client
1264 * @param buffer pointer to a request buffer
1265 * @param size size (in bytes) of request buffer
1266 *
1267 * @return 0 on success, <0 on error.
1268 */
1269int smsclient_sendrequest(struct smscore_client_t *client,
1270                          void *buffer, size_t size)
1271{
1272        struct smscore_device_t *coredev;
1273        struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1274        int rc;
1275
1276        if (client == NULL) {
1277                sms_err("Got NULL client");
1278                return -EINVAL;
1279        }
1280
1281        coredev = client->coredev;
1282
1283        /* check that no other channel with same id exists */
1284        if (coredev == NULL) {
1285                sms_err("Got NULL coredev");
1286                return -EINVAL;
1287        }
1288
1289        rc = smscore_validate_client(client->coredev, client, 0,
1290                                     phdr->msgSrcId);
1291        if (rc < 0)
1292                return rc;
1293
1294        return coredev->sendrequest_handler(coredev->context, buffer, size);
1295}
1296EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1297
1298
1299/* old GPIO managments implementation */
1300int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1301                           struct smscore_config_gpio *pinconfig)
1302{
1303        struct {
1304                struct SmsMsgHdr_ST hdr;
1305                u32 data[6];
1306        } msg;
1307
1308        if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1309                msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1310                msg.hdr.msgDstId = HIF_TASK;
1311                msg.hdr.msgFlags = 0;
1312                msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
1313                msg.hdr.msgLength = sizeof(msg);
1314
1315                msg.data[0] = pin;
1316                msg.data[1] = pinconfig->pullupdown;
1317
1318                /* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1319                msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1320
1321                switch (pinconfig->outputdriving) {
1322                case SMS_GPIO_OUTPUTDRIVING_16mA:
1323                        msg.data[3] = 7; /* Nova - 16mA */
1324                        break;
1325                case SMS_GPIO_OUTPUTDRIVING_12mA:
1326                        msg.data[3] = 5; /* Nova - 11mA */
1327                        break;
1328                case SMS_GPIO_OUTPUTDRIVING_8mA:
1329                        msg.data[3] = 3; /* Nova - 7mA */
1330                        break;
1331                case SMS_GPIO_OUTPUTDRIVING_4mA:
1332                default:
1333                        msg.data[3] = 2; /* Nova - 4mA */
1334                        break;
1335                }
1336
1337                msg.data[4] = pinconfig->direction;
1338                msg.data[5] = 0;
1339        } else /* TODO: SMS_DEVICE_FAMILY1 */
1340                return -EINVAL;
1341
1342        return coredev->sendrequest_handler(coredev->context,
1343                                            &msg, sizeof(msg));
1344}
1345
1346int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1347{
1348        struct {
1349                struct SmsMsgHdr_ST hdr;
1350                u32 data[3];
1351        } msg;
1352
1353        if (pin > MAX_GPIO_PIN_NUMBER)
1354                return -EINVAL;
1355
1356        msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1357        msg.hdr.msgDstId = HIF_TASK;
1358        msg.hdr.msgFlags = 0;
1359        msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
1360        msg.hdr.msgLength = sizeof(msg);
1361
1362        msg.data[0] = pin;
1363        msg.data[1] = level ? 1 : 0;
1364        msg.data[2] = 0;
1365
1366        return coredev->sendrequest_handler(coredev->context,
1367                                            &msg, sizeof(msg));
1368}
1369
1370/* new GPIO management implementation */
1371static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1372                u32 *pGroupNum, u32 *pGroupCfg) {
1373
1374        *pGroupCfg = 1;
1375
1376        if (PinNum >= 0 && PinNum <= 1) {
1377                *pTranslatedPinNum = 0;
1378                *pGroupNum = 9;
1379                *pGroupCfg = 2;
1380        } else if (PinNum >= 2 && PinNum <= 6) {
1381                *pTranslatedPinNum = 2;
1382                *pGroupNum = 0;
1383                *pGroupCfg = 2;
1384        } else if (PinNum >= 7 && PinNum <= 11) {
1385                *pTranslatedPinNum = 7;
1386                *pGroupNum = 1;
1387        } else if (PinNum >= 12 && PinNum <= 15) {
1388                *pTranslatedPinNum = 12;
1389                *pGroupNum = 2;
1390                *pGroupCfg = 3;
1391        } else if (PinNum == 16) {
1392                *pTranslatedPinNum = 16;
1393                *pGroupNum = 23;
1394        } else if (PinNum >= 17 && PinNum <= 24) {
1395                *pTranslatedPinNum = 17;
1396                *pGroupNum = 3;
1397        } else if (PinNum == 25) {
1398                *pTranslatedPinNum = 25;
1399                *pGroupNum = 6;
1400        } else if (PinNum >= 26 && PinNum <= 28) {
1401                *pTranslatedPinNum = 26;
1402                *pGroupNum = 4;
1403        } else if (PinNum == 29) {
1404                *pTranslatedPinNum = 29;
1405                *pGroupNum = 5;
1406                *pGroupCfg = 2;
1407        } else if (PinNum == 30) {
1408                *pTranslatedPinNum = 30;
1409                *pGroupNum = 8;
1410        } else if (PinNum == 31) {
1411                *pTranslatedPinNum = 31;
1412                *pGroupNum = 17;
1413        } else
1414                return -1;
1415
1416        *pGroupCfg <<= 24;
1417
1418        return 0;
1419}
1420
1421int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1422                struct smscore_gpio_config *pGpioConfig) {
1423
1424        u32 totalLen;
1425        u32 TranslatedPinNum = 0;
1426        u32 GroupNum = 0;
1427        u32 ElectricChar;
1428        u32 groupCfg;
1429        void *buffer;
1430        int rc;
1431
1432        struct SetGpioMsg {
1433                struct SmsMsgHdr_ST xMsgHeader;
1434                u32 msgData[6];
1435        } *pMsg;
1436
1437
1438        if (PinNum > MAX_GPIO_PIN_NUMBER)
1439                return -EINVAL;
1440
1441        if (pGpioConfig == NULL)
1442                return -EINVAL;
1443
1444        totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1445
1446        buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1447                        GFP_KERNEL | GFP_DMA);
1448        if (!buffer)
1449                return -ENOMEM;
1450
1451        pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1452
1453        pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1454        pMsg->xMsgHeader.msgDstId = HIF_TASK;
1455        pMsg->xMsgHeader.msgFlags = 0;
1456        pMsg->xMsgHeader.msgLength = (u16) totalLen;
1457        pMsg->msgData[0] = PinNum;
1458
1459        if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1460                pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1461                if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
1462                                &groupCfg) != 0)
1463                        return -EINVAL;
1464
1465                pMsg->msgData[1] = TranslatedPinNum;
1466                pMsg->msgData[2] = GroupNum;
1467                ElectricChar = (pGpioConfig->PullUpDown)
1468                                | (pGpioConfig->InputCharacteristics << 2)
1469                                | (pGpioConfig->OutputSlewRate << 3)
1470                                | (pGpioConfig->OutputDriving << 4);
1471                pMsg->msgData[3] = ElectricChar;
1472                pMsg->msgData[4] = pGpioConfig->Direction;
1473                pMsg->msgData[5] = groupCfg;
1474        } else {
1475                pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1476                pMsg->msgData[1] = pGpioConfig->PullUpDown;
1477                pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
1478                pMsg->msgData[3] = pGpioConfig->OutputDriving;
1479                pMsg->msgData[4] = pGpioConfig->Direction;
1480                pMsg->msgData[5] = 0;
1481        }
1482
1483        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1484        rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1485                        &coredev->gpio_configuration_done);
1486
1487        if (rc != 0) {
1488                if (rc == -ETIME)
1489                        sms_err("smscore_gpio_configure timeout");
1490                else
1491                        sms_err("smscore_gpio_configure error");
1492        }
1493        kfree(buffer);
1494
1495        return rc;
1496}
1497
1498int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1499                u8 NewLevel) {
1500
1501        u32 totalLen;
1502        int rc;
1503        void *buffer;
1504
1505        struct SetGpioMsg {
1506                struct SmsMsgHdr_ST xMsgHeader;
1507                u32 msgData[3]; /* keep it 3 ! */
1508        } *pMsg;
1509
1510        if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
1511                        (PinNum > MAX_GPIO_PIN_NUMBER))
1512                return -EINVAL;
1513
1514        totalLen = sizeof(struct SmsMsgHdr_ST) +
1515                        (3 * sizeof(u32)); /* keep it 3 ! */
1516
1517        buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1518                        GFP_KERNEL | GFP_DMA);
1519        if (!buffer)
1520                return -ENOMEM;
1521
1522        pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1523
1524        pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1525        pMsg->xMsgHeader.msgDstId = HIF_TASK;
1526        pMsg->xMsgHeader.msgFlags = 0;
1527        pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1528        pMsg->xMsgHeader.msgLength = (u16) totalLen;
1529        pMsg->msgData[0] = PinNum;
1530        pMsg->msgData[1] = NewLevel;
1531
1532        /* Send message to SMS */
1533        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1534        rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1535                        &coredev->gpio_set_level_done);
1536
1537        if (rc != 0) {
1538                if (rc == -ETIME)
1539                        sms_err("smscore_gpio_set_level timeout");
1540                else
1541                        sms_err("smscore_gpio_set_level error");
1542        }
1543        kfree(buffer);
1544
1545        return rc;
1546}
1547
1548int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1549                u8 *level) {
1550
1551        u32 totalLen;
1552        int rc;
1553        void *buffer;
1554
1555        struct SetGpioMsg {
1556                struct SmsMsgHdr_ST xMsgHeader;
1557                u32 msgData[2];
1558        } *pMsg;
1559
1560
1561        if (PinNum > MAX_GPIO_PIN_NUMBER)
1562                return -EINVAL;
1563
1564        totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1565
1566        buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1567                        GFP_KERNEL | GFP_DMA);
1568        if (!buffer)
1569                return -ENOMEM;
1570
1571        pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1572
1573        pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1574        pMsg->xMsgHeader.msgDstId = HIF_TASK;
1575        pMsg->xMsgHeader.msgFlags = 0;
1576        pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
1577        pMsg->xMsgHeader.msgLength = (u16) totalLen;
1578        pMsg->msgData[0] = PinNum;
1579        pMsg->msgData[1] = 0;
1580
1581        /* Send message to SMS */
1582        smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1583        rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1584                        &coredev->gpio_get_level_done);
1585
1586        if (rc != 0) {
1587                if (rc == -ETIME)
1588                        sms_err("smscore_gpio_get_level timeout");
1589                else
1590                        sms_err("smscore_gpio_get_level error");
1591        }
1592        kfree(buffer);
1593
1594        /* Its a race between other gpio_get_level() and the copy of the single
1595         * global 'coredev->gpio_get_res' to  the function's variable 'level'
1596         */
1597        *level = coredev->gpio_get_res;
1598
1599        return rc;
1600}
1601
1602static int __init smscore_module_init(void)
1603{
1604        int rc = 0;
1605
1606        INIT_LIST_HEAD(&g_smscore_notifyees);
1607        INIT_LIST_HEAD(&g_smscore_devices);
1608        kmutex_init(&g_smscore_deviceslock);
1609
1610        INIT_LIST_HEAD(&g_smscore_registry);
1611        kmutex_init(&g_smscore_registrylock);
1612
1613        return rc;
1614}
1615
1616static void __exit smscore_module_exit(void)
1617{
1618        kmutex_lock(&g_smscore_deviceslock);
1619        while (!list_empty(&g_smscore_notifyees)) {
1620                struct smscore_device_notifyee_t *notifyee =
1621                        (struct smscore_device_notifyee_t *)
1622                                g_smscore_notifyees.next;
1623
1624                list_del(&notifyee->entry);
1625                kfree(notifyee);
1626        }
1627        kmutex_unlock(&g_smscore_deviceslock);
1628
1629        kmutex_lock(&g_smscore_registrylock);
1630        while (!list_empty(&g_smscore_registry)) {
1631                struct smscore_registry_entry_t *entry =
1632                        (struct smscore_registry_entry_t *)
1633                                g_smscore_registry.next;
1634
1635                list_del(&entry->entry);
1636                kfree(entry);
1637        }
1638        kmutex_unlock(&g_smscore_registrylock);
1639
1640        sms_debug("");
1641}
1642
1643module_init(smscore_module_init);
1644module_exit(smscore_module_exit);
1645
1646MODULE_DESCRIPTION("Siano MDTV Core module");
1647MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1648MODULE_LICENSE("GPL");
1649