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