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