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