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