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