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