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