V4L/DVB (8303): sms1xxx: update MODULE_DESCRIPTION
[deliverable/linux.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;
115kmutex_t g_smscore_deviceslock;
116
117struct list_head g_smscore_registry;
118kmutex_t g_smscore_registrylock;
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 }
02aea4fb 604 sms_info("read FW %s, size=%d", 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) {
02aea4fb
MK
794 sms_err("error %d loading firmware: %s, "
795 "trying again with default firmware",
796 rc, fw_filename);
797
798 /* try again with the default firmware */
799 rc = smscore_load_firmware_from_file(coredev,
800 smscore_fw_lkup[mode][type], NULL);
801
802 if (rc < 0) {
803 sms_err("load firmware failed %d", rc);
804 return rc;
805 }
82237416
MK
806 }
807 } else
a0c0abcb
MK
808 sms_info("mode %d supported by running "
809 "firmware", mode);
2e5c1ec8 810
18245e18
MK
811 buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
812 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
82237416 813 if (buffer) {
18245e18
MK
814 struct SmsMsgData_ST *msg =
815 (struct SmsMsgData_ST *)
816 SMS_ALIGN_ADDRESS(buffer);
2e5c1ec8 817
59bf6b8e 818 SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
18245e18 819 sizeof(struct SmsMsgData_ST));
2e5c1ec8
MK
820 msg->msgData[0] = mode;
821
59bf6b8e
MK
822 rc = smscore_sendrequest_and_wait(
823 coredev, msg, msg->xMsgHeader.msgLength,
824 &coredev->init_device_done);
2e5c1ec8
MK
825
826 kfree(buffer);
82237416 827 } else {
eb250942
MK
828 sms_err("Could not allocate buffer for "
829 "init device message.");
2e5c1ec8 830 rc = -ENOMEM;
82237416
MK
831 }
832 } else {
833 if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
eb250942 834 sms_err("invalid mode specified %d", mode);
f17407a8
MK
835 return -EINVAL;
836 }
837
838 smscore_registry_setmode(coredev->devpath, mode);
839
2e5c1ec8 840 if (coredev->detectmode_handler)
82237416
MK
841 coredev->detectmode_handler(coredev->context,
842 &coredev->mode);
2e5c1ec8
MK
843
844 if (coredev->mode != mode && coredev->setmode_handler)
845 rc = coredev->setmode_handler(coredev->context, mode);
846 }
847
82237416 848 if (rc >= 0) {
2e5c1ec8
MK
849 coredev->mode = mode;
850 coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
851 }
852
f17407a8 853 if (rc != 0)
eb250942 854 sms_err("return error code %d.", rc);
2e5c1ec8
MK
855 return rc;
856}
857
858/**
859 * calls device handler to get current mode of operation
860 *
59bf6b8e
MK
861 * @param coredev pointer to a coredev object returned by
862 * smscore_register_device
2e5c1ec8
MK
863 *
864 * @return current mode
865 */
18245e18 866int smscore_get_device_mode(struct smscore_device_t *coredev)
2e5c1ec8
MK
867{
868 return coredev->mode;
869}
870
f17407a8
MK
871/**
872 * find client by response id & type within the clients list.
873 * return client handle or NULL.
874 *
59bf6b8e
MK
875 * @param coredev pointer to a coredev object returned by
876 * smscore_register_device
f17407a8 877 * @param data_type client data type (SMS_DONT_CARE for all types)
82237416 878 * @param id client id (SMS_DONT_CARE for all id)
f17407a8
MK
879 *
880 */
0c071f37
MK
881static struct
882smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
59bf6b8e 883 int data_type, int id)
2e5c1ec8 884{
18245e18 885 struct smscore_client_t *client = NULL;
2e5c1ec8
MK
886 struct list_head *next, *first;
887 unsigned long flags;
f17407a8 888 struct list_head *firstid, *nextid;
2e5c1ec8 889
2e5c1ec8
MK
890
891 spin_lock_irqsave(&coredev->clientslock, flags);
2e5c1ec8 892 first = &coredev->clients;
82237416
MK
893 for (next = first->next;
894 (next != first) && !client;
895 next = next->next) {
18245e18 896 firstid = &((struct smscore_client_t *)next)->idlist;
82237416
MK
897 for (nextid = firstid->next;
898 nextid != firstid;
899 nextid = nextid->next) {
18245e18
MK
900 if ((((struct smscore_idlist_t *)nextid)->id == id) &&
901 (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
902 (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
903 client = (struct smscore_client_t *) next;
82237416
MK
904 break;
905 }
2e5c1ec8
MK
906 }
907 }
2e5c1ec8 908 spin_unlock_irqrestore(&coredev->clientslock, flags);
2e5c1ec8
MK
909 return client;
910}
911
912/**
913 * find client by response id/type, call clients onresponse handler
914 * return buffer to pool on error
915 *
59bf6b8e
MK
916 * @param coredev pointer to a coredev object returned by
917 * smscore_register_device
2e5c1ec8
MK
918 * @param cb pointer to response buffer descriptor
919 *
920 */
18245e18
MK
921void smscore_onresponse(struct smscore_device_t *coredev,
922 struct smscore_buffer_t *cb)
2e5c1ec8 923{
18245e18
MK
924 struct SmsMsgHdr_ST *phdr =
925 (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
926 struct smscore_client_t *client =
59bf6b8e 927 smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
2e5c1ec8
MK
928 int rc = -EBUSY;
929
fbd05c82
MK
930 static unsigned long last_sample_time; /* = 0; */
931 static int data_total; /* = 0; */
2e5c1ec8
MK
932 unsigned long time_now = jiffies_to_msecs(jiffies);
933
934 if (!last_sample_time)
935 last_sample_time = time_now;
936
fa830e8a 937 if (time_now - last_sample_time > 10000) {
a0c0abcb 938 sms_debug("\ndata rate %d bytes/secs",
068d6c0f
MK
939 (int)((data_total * 1000) /
940 (time_now - last_sample_time)));
2e5c1ec8
MK
941
942 last_sample_time = time_now;
943 data_total = 0;
944 }
945
946 data_total += cb->size;
82237416
MK
947 /* If no client registered for type & id,
948 * check for control client where type is not registered */
2e5c1ec8
MK
949 if (client)
950 rc = client->onresponse_handler(client->context, cb);
951
82237416
MK
952 if (rc < 0) {
953 switch (phdr->msgType) {
954 case MSG_SMS_GET_VERSION_EX_RES:
2e5c1ec8 955 {
18245e18
MK
956 struct SmsVersionRes_ST *ver =
957 (struct SmsVersionRes_ST *) phdr;
a0c0abcb
MK
958 sms_debug("MSG_SMS_GET_VERSION_EX_RES "
959 "id %d prots 0x%x ver %d.%d",
068d6c0f
MK
960 ver->FirmwareId, ver->SupportedProtocols,
961 ver->RomVersionMajor, ver->RomVersionMinor);
2e5c1ec8 962
82237416
MK
963 coredev->mode = ver->FirmwareId == 255 ?
964 DEVICE_MODE_NONE : ver->FirmwareId;
965 coredev->modes_supported = ver->SupportedProtocols;
2e5c1ec8 966
82237416
MK
967 complete(&coredev->version_ex_done);
968 break;
969 }
970 case MSG_SMS_INIT_DEVICE_RES:
a0c0abcb 971 sms_debug("MSG_SMS_INIT_DEVICE_RES");
82237416
MK
972 complete(&coredev->init_device_done);
973 break;
974 case MSG_SW_RELOAD_START_RES:
a0c0abcb 975 sms_debug("MSG_SW_RELOAD_START_RES");
82237416
MK
976 complete(&coredev->reload_start_done);
977 break;
978 case MSG_SMS_DATA_DOWNLOAD_RES:
979 complete(&coredev->data_download_done);
980 break;
981 case MSG_SW_RELOAD_EXEC_RES:
a0c0abcb 982 sms_debug("MSG_SW_RELOAD_EXEC_RES");
82237416
MK
983 break;
984 case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
a0c0abcb 985 sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
82237416
MK
986 complete(&coredev->trigger_done);
987 break;
988 case MSG_SMS_SLEEP_RESUME_COMP_IND:
989 complete(&coredev->resume_done);
990 break;
991 default:
992 break;
2e5c1ec8 993 }
2e5c1ec8
MK
994 smscore_putbuffer(coredev, cb);
995 }
996}
997
998/**
999 * return pointer to next free buffer descriptor from core pool
1000 *
59bf6b8e
MK
1001 * @param coredev pointer to a coredev object returned by
1002 * smscore_register_device
2e5c1ec8
MK
1003 *
1004 * @return pointer to descriptor on success, NULL on error.
1005 */
18245e18 1006struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
2e5c1ec8 1007{
18245e18 1008 struct smscore_buffer_t *cb = NULL;
2e5c1ec8
MK
1009 unsigned long flags;
1010
1011 spin_lock_irqsave(&coredev->bufferslock, flags);
1012
82237416 1013 if (!list_empty(&coredev->buffers)) {
18245e18 1014 cb = (struct smscore_buffer_t *) coredev->buffers.next;
2e5c1ec8
MK
1015 list_del(&cb->entry);
1016 }
1017
1018 spin_unlock_irqrestore(&coredev->bufferslock, flags);
1019
1020 return cb;
1021}
1022
1023/**
1024 * return buffer descriptor to a pool
1025 *
59bf6b8e
MK
1026 * @param coredev pointer to a coredev object returned by
1027 * smscore_register_device
2e5c1ec8
MK
1028 * @param cb pointer buffer descriptor
1029 *
1030 */
18245e18
MK
1031void smscore_putbuffer(struct smscore_device_t *coredev,
1032 struct smscore_buffer_t *cb)
2e5c1ec8
MK
1033{
1034 list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1035}
1036
0c071f37
MK
1037static int smscore_validate_client(struct smscore_device_t *coredev,
1038 struct smscore_client_t *client,
1039 int data_type, int id)
2e5c1ec8 1040{
18245e18
MK
1041 struct smscore_idlist_t *listentry;
1042 struct smscore_client_t *registered_client;
2e5c1ec8 1043
82237416 1044 if (!client) {
2522dc13 1045 sms_err("bad parameter.");
f17407a8
MK
1046 return -EFAULT;
1047 }
1048 registered_client = smscore_find_client(coredev, data_type, id);
fa830e8a 1049 if (registered_client == client)
2e5c1ec8 1050 return 0;
fa830e8a 1051
82237416 1052 if (registered_client) {
2522dc13 1053 sms_err("The msg ID already registered to another client.");
f17407a8
MK
1054 return -EEXIST;
1055 }
18245e18 1056 listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
82237416 1057 if (!listentry) {
2522dc13 1058 sms_err("Can't allocate memory for client id.");
2e5c1ec8 1059 return -ENOMEM;
f17407a8
MK
1060 }
1061 listentry->id = id;
1062 listentry->data_type = data_type;
82237416
MK
1063 list_add_locked(&listentry->entry, &client->idlist,
1064 &coredev->clientslock);
2e5c1ec8
MK
1065 return 0;
1066}
1067
1068/**
1069 * creates smsclient object, check that id is taken by another client
1070 *
1071 * @param coredev pointer to a coredev object from clients hotplug
1072 * @param initial_id all messages with this id would be sent to this client
1073 * @param data_type all messages of this type would be sent to this client
ca783736
MK
1074 * @param onresponse_handler client handler that is called to
1075 * process incoming messages
2e5c1ec8
MK
1076 * @param onremove_handler client handler that is called when device is removed
1077 * @param context client-specific context
1078 * @param client pointer to a value that receives created smsclient object
1079 *
1080 * @return 0 on success, <0 on error.
1081 */
18245e18
MK
1082int smscore_register_client(struct smscore_device_t *coredev,
1083 struct smsclient_params_t *params,
1084 struct smscore_client_t **client)
2e5c1ec8 1085{
18245e18 1086 struct smscore_client_t *newclient;
82237416
MK
1087 /* check that no other channel with same parameters exists */
1088 if (smscore_find_client(coredev, params->data_type,
1089 params->initial_id)) {
2522dc13 1090 sms_err("Client already exist.");
2e5c1ec8 1091 return -EEXIST;
f17407a8 1092 }
2e5c1ec8 1093
18245e18 1094 newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
82237416 1095 if (!newclient) {
2522dc13 1096 sms_err("Failed to allocate memory for client.");
f17407a8 1097 return -ENOMEM;
2e5c1ec8
MK
1098 }
1099
82237416 1100 INIT_LIST_HEAD(&newclient->idlist);
2e5c1ec8 1101 newclient->coredev = coredev;
2e5c1ec8
MK
1102 newclient->onresponse_handler = params->onresponse_handler;
1103 newclient->onremove_handler = params->onremove_handler;
1104 newclient->context = params->context;
82237416
MK
1105 list_add_locked(&newclient->entry, &coredev->clients,
1106 &coredev->clientslock);
1107 smscore_validate_client(coredev, newclient, params->data_type,
1108 params->initial_id);
2e5c1ec8 1109 *client = newclient;
2522dc13
MK
1110 sms_debug("%p %d %d", params->context, params->data_type,
1111 params->initial_id);
2e5c1ec8
MK
1112
1113 return 0;
1114}
1115
1116/**
1117 * frees smsclient object and all subclients associated with it
1118 *
59bf6b8e
MK
1119 * @param client pointer to smsclient object returned by
1120 * smscore_register_client
2e5c1ec8
MK
1121 *
1122 */
18245e18 1123void smscore_unregister_client(struct smscore_client_t *client)
2e5c1ec8 1124{
18245e18 1125 struct smscore_device_t *coredev = client->coredev;
2e5c1ec8
MK
1126 unsigned long flags;
1127
1128 spin_lock_irqsave(&coredev->clientslock, flags);
1129
2e5c1ec8 1130
82237416 1131 while (!list_empty(&client->idlist)) {
18245e18
MK
1132 struct smscore_idlist_t *identry =
1133 (struct smscore_idlist_t *) client->idlist.next;
82237416
MK
1134 list_del(&identry->entry);
1135 kfree(identry);
2e5c1ec8
MK
1136 }
1137
a0c0abcb 1138 sms_info("%p", client->context);
2e5c1ec8
MK
1139
1140 list_del(&client->entry);
1141 kfree(client);
1142
1143 spin_unlock_irqrestore(&coredev->clientslock, flags);
1144}
1145
1146/**
1147 * verifies that source id is not taken by another client,
1148 * calls device handler to send requests to the device
1149 *
59bf6b8e
MK
1150 * @param client pointer to smsclient object returned by
1151 * smscore_register_client
2e5c1ec8
MK
1152 * @param buffer pointer to a request buffer
1153 * @param size size (in bytes) of request buffer
1154 *
1155 * @return 0 on success, <0 on error.
1156 */
18245e18
MK
1157int smsclient_sendrequest(struct smscore_client_t *client,
1158 void *buffer, size_t size)
2e5c1ec8 1159{
18245e18
MK
1160 struct smscore_device_t *coredev;
1161 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
f17407a8
MK
1162 int rc;
1163
82237416 1164 if (client == NULL) {
a0c0abcb 1165 sms_err("Got NULL client");
f17407a8
MK
1166 return -EINVAL;
1167 }
1168
1169 coredev = client->coredev;
2e5c1ec8 1170
82237416
MK
1171 /* check that no other channel with same id exists */
1172 if (coredev == NULL) {
a0c0abcb 1173 sms_err("Got NULL coredev");
f17407a8
MK
1174 return -EINVAL;
1175 }
1176
82237416
MK
1177 rc = smscore_validate_client(client->coredev, client, 0,
1178 phdr->msgSrcId);
2e5c1ec8
MK
1179 if (rc < 0)
1180 return rc;
1181
1182 return coredev->sendrequest_handler(coredev->context, buffer, size);
1183}
1184
2e5c1ec8
MK
1185
1186int smscore_module_init(void)
1187{
c6465799 1188 int rc = 0;
2e5c1ec8
MK
1189
1190 INIT_LIST_HEAD(&g_smscore_notifyees);
1191 INIT_LIST_HEAD(&g_smscore_devices);
1192 kmutex_init(&g_smscore_deviceslock);
1193
1194 INIT_LIST_HEAD(&g_smscore_registry);
1195 kmutex_init(&g_smscore_registrylock);
1196
eae55660
ST
1197 /* USB Register */
1198 rc = smsusb_register();
1199
1200 /* DVB Register */
1201 rc = smsdvb_register();
1202
a0c0abcb 1203 sms_debug("rc %d", rc);
2e5c1ec8
MK
1204
1205 return rc;
1206}
1207
1208void smscore_module_exit(void)
1209{
eae55660 1210
2e5c1ec8 1211 kmutex_lock(&g_smscore_deviceslock);
82237416 1212 while (!list_empty(&g_smscore_notifyees)) {
18245e18
MK
1213 struct smscore_device_notifyee_t *notifyee =
1214 (struct smscore_device_notifyee_t *)
1215 g_smscore_notifyees.next;
2e5c1ec8
MK
1216
1217 list_del(&notifyee->entry);
1218 kfree(notifyee);
1219 }
1220 kmutex_unlock(&g_smscore_deviceslock);
1221
1222 kmutex_lock(&g_smscore_registrylock);
82237416 1223 while (!list_empty(&g_smscore_registry)) {
18245e18
MK
1224 struct smscore_registry_entry_t *entry =
1225 (struct smscore_registry_entry_t *)
1226 g_smscore_registry.next;
2e5c1ec8
MK
1227
1228 list_del(&entry->entry);
1229 kfree(entry);
1230 }
1231 kmutex_unlock(&g_smscore_registrylock);
1232
eae55660
ST
1233 /* DVB UnRegister */
1234 smsdvb_unregister();
1235
1236 /* Unregister USB */
1237 smsusb_unregister();
1238
a0c0abcb 1239 sms_debug("");
2e5c1ec8
MK
1240}
1241
1242module_init(smscore_module_init);
1243module_exit(smscore_module_exit);
1244
8f37356b 1245MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
82237416 1246MODULE_AUTHOR("Siano Mobile Silicon,,, (doronc@siano-ms.com)");
2e5c1ec8 1247MODULE_LICENSE("GPL");
This page took 0.097072 seconds and 5 git commands to generate.