smscoreapi.c 33.2 KB
Newer Older
1
/*
2 3 4 5
 *  Siano core API module
 *
 *  This file contains implementation for the interface to sms core component
 *
6
 *  author: Uri Shkolnik
7
 *
8
 *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
9 10
 *
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License version 2 as
12
 *  published by the Free Software Foundation;
13
 *
14 15
 *  Software distributed under the License is distributed on an "AS IS"
 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
16
 *
17
 *  See the GNU General Public License for more details.
18 19 20 21 22 23
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

24 25 26 27 28 29
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
30
#include <linux/io.h>
31 32 33 34

#include <linux/firmware.h>

#include "smscoreapi.h"
35
#include "sms-cards.h"
36

37
static int sms_dbg;
38
module_param_named(debug, sms_dbg, int, 0644);
39 40
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");

41
struct smscore_device_notifyee_t {
42 43
	struct list_head entry;
	hotplug_t hotplug;
44
};
45

46
struct smscore_idlist_t {
47 48 49
	struct list_head entry;
	int		id;
	int		data_type;
50
};
51

52
struct smscore_client_t {
53
	struct list_head entry;
54
	struct smscore_device_t *coredev;
55
	void			*context;
56
	struct list_head 	idlist;
57 58
	onresponse_t	onresponse_handler;
	onremove_t		onremove_handler;
59
};
60

61 62 63 64 65
void smscore_set_board_id(struct smscore_device_t *core, int id)
{
	core->board_id = id;
}

66 67 68 69 70 71
int smscore_led_state(struct smscore_device_t *core, int led)
{
	if (led >= 0)
		core->led_state = led;
	return core->led_state;
}
72
EXPORT_SYMBOL_GPL(smscore_set_board_id);
73

74 75 76 77
int smscore_get_board_id(struct smscore_device_t *core)
{
	return core->board_id;
}
78
EXPORT_SYMBOL_GPL(smscore_get_board_id);
79

80
struct smscore_registry_entry_t {
81 82 83
	struct list_head entry;
	char			devpath[32];
	int				mode;
84 85
	enum sms_device_type_st	type;
};
86

87 88 89
static struct list_head g_smscore_notifyees;
static struct list_head g_smscore_devices;
static struct mutex g_smscore_deviceslock;
90

91 92
static struct list_head g_smscore_registry;
static struct mutex g_smscore_registrylock;
93

94
static int default_mode = 4;
95

96 97 98
module_param(default_mode, int, 0644);
MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");

99
static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
100
{
101
	struct smscore_registry_entry_t *entry;
102 103 104
	struct list_head *next;

	kmutex_lock(&g_smscore_registrylock);
105 106 107
	for (next = g_smscore_registry.next;
	     next != &g_smscore_registry;
	     next = next->next) {
108
		entry = (struct smscore_registry_entry_t *) next;
109
		if (!strcmp(entry->devpath, devpath)) {
110
			kmutex_unlock(&g_smscore_registrylock);
111
			return entry;
112 113
		}
	}
114 115 116
	entry = (struct smscore_registry_entry_t *)
			kmalloc(sizeof(struct smscore_registry_entry_t),
				GFP_KERNEL);
117
	if (entry) {
118 119 120
		entry->mode = default_mode;
		strcpy(entry->devpath, devpath);
		list_add(&entry->entry, &g_smscore_registry);
121
	} else
122
		sms_err("failed to create smscore_registry.");
123
	kmutex_unlock(&g_smscore_registrylock);
124 125
	return entry;
}
126

127
int smscore_registry_getmode(char *devpath)
128
{
129
	struct smscore_registry_entry_t *entry;
130

131 132
	entry = smscore_find_registry(devpath);
	if (entry)
133 134
		return entry->mode;
	else
135
		sms_err("No registry found.");
136

137 138
	return default_mode;
}
139
EXPORT_SYMBOL_GPL(smscore_registry_getmode);
140

141
static enum sms_device_type_st smscore_registry_gettype(char *devpath)
142
{
143
	struct smscore_registry_entry_t *entry;
144

145 146
	entry = smscore_find_registry(devpath);
	if (entry)
147 148
		return entry->type;
	else
149
		sms_err("No registry found.");
150

151 152
	return -1;
}
153

154 155
void smscore_registry_setmode(char *devpath, int mode)
{
156
	struct smscore_registry_entry_t *entry;
157

158 159 160
	entry = smscore_find_registry(devpath);
	if (entry)
		entry->mode = mode;
161
	else
162
		sms_err("No registry found.");
163
}
164

165 166
static void smscore_registry_settype(char *devpath,
				     enum sms_device_type_st type)
167
{
168
	struct smscore_registry_entry_t *entry;
169

170 171
	entry = smscore_find_registry(devpath);
	if (entry)
172 173
		entry->type = type;
	else
174
		sms_err("No registry found.");
175 176 177
}


178 179
static void list_add_locked(struct list_head *new, struct list_head *head,
			    spinlock_t *lock)
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
{
	unsigned long flags;

	spin_lock_irqsave(lock, flags);

	list_add(new, head);

	spin_unlock_irqrestore(lock, flags);
}

/**
 * register a client callback that called when device plugged in/unplugged
 * NOTE: if devices exist callback is called immediately for each device
 *
 * @param hotplug callback
 *
 * @return 0 on success, <0 on error.
 */
int smscore_register_hotplug(hotplug_t hotplug)
{
200
	struct smscore_device_notifyee_t *notifyee;
201 202 203 204 205
	struct list_head *next, *first;
	int rc = 0;

	kmutex_lock(&g_smscore_deviceslock);

206 207
	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
			   GFP_KERNEL);
208 209
	if (notifyee) {
		/* now notify callback about existing devices */
210
		first = &g_smscore_devices;
211 212 213
		for (next = first->next;
		     next != first && !rc;
		     next = next->next) {
214 215
			struct smscore_device_t *coredev =
				(struct smscore_device_t *) next;
216 217 218
			rc = hotplug(coredev, coredev->device, 1);
		}

219
		if (rc >= 0) {
220 221
			notifyee->hotplug = hotplug;
			list_add(&notifyee->entry, &g_smscore_notifyees);
222
		} else
223
			kfree(notifyee);
224
	} else
225 226 227 228 229 230
		rc = -ENOMEM;

	kmutex_unlock(&g_smscore_deviceslock);

	return rc;
}
231
EXPORT_SYMBOL_GPL(smscore_register_hotplug);
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

/**
 * unregister a client callback that called when device plugged in/unplugged
 *
 * @param hotplug callback
 *
 */
void smscore_unregister_hotplug(hotplug_t hotplug)
{
	struct list_head *next, *first;

	kmutex_lock(&g_smscore_deviceslock);

	first = &g_smscore_notifyees;

247
	for (next = first->next; next != first;) {
248 249
		struct smscore_device_notifyee_t *notifyee =
			(struct smscore_device_notifyee_t *) next;
250 251
		next = next->next;

252
		if (notifyee->hotplug == hotplug) {
253 254 255 256 257 258 259
			list_del(&notifyee->entry);
			kfree(notifyee);
		}
	}

	kmutex_unlock(&g_smscore_deviceslock);
}
260
EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
261

262
static void smscore_notify_clients(struct smscore_device_t *coredev)
263
{
264
	struct smscore_client_t *client;
265

266 267
	/* the client must call smscore_unregister_client from remove handler */
	while (!list_empty(&coredev->clients)) {
268
		client = (struct smscore_client_t *) coredev->clients.next;
269 270 271 272
		client->onremove_handler(client->context);
	}
}

273 274
static int smscore_notify_callbacks(struct smscore_device_t *coredev,
				    struct device *device, int arrival)
275 276 277 278
{
	struct list_head *next, *first;
	int rc = 0;

279
	/* note: must be called under g_deviceslock */
280 281 282

	first = &g_smscore_notifyees;

283
	for (next = first->next; next != first; next = next->next) {
284
		rc = ((struct smscore_device_notifyee_t *) next)->
285
				hotplug(coredev, device, arrival);
286 287 288 289 290 291 292
		if (rc < 0)
			break;
	}

	return rc;
}

293 294
static struct
smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
295
				       dma_addr_t common_buffer_phys)
296
{
297 298
	struct smscore_buffer_t *cb =
		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
299
	if (!cb) {
300
		sms_info("kmalloc(...) failed");
301 302 303 304
		return NULL;
	}

	cb->p = buffer;
305
	cb->offset_in_common = buffer - (u8 *) common_buffer;
306 307 308 309 310 311
	cb->phys = common_buffer_phys + cb->offset_in_common;

	return cb;
}

/**
312 313
 * creates coredev object for a device, prepares buffers,
 * creates buffer mappings, notifies registered hotplugs about new device.
314
 *
315 316
 * @param params device pointer to struct with device specific parameters
 *               and handlers
317 318 319 320
 * @param coredev pointer to a value that receives created coredev object
 *
 * @return 0 on success, <0 on error.
 */
321 322
int smscore_register_device(struct smsdevice_params_t *params,
			    struct smscore_device_t **coredev)
323
{
324
	struct smscore_device_t *dev;
325 326
	u8 *buffer;

327
	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
328
	if (!dev) {
329
		sms_info("kzalloc(...) failed");
330 331 332
		return -ENOMEM;
	}

333
	/* init list entry so it could be safe in smscore_unregister_device */
334 335
	INIT_LIST_HEAD(&dev->entry);

336
	/* init queues */
337 338 339
	INIT_LIST_HEAD(&dev->clients);
	INIT_LIST_HEAD(&dev->buffers);

340
	/* init locks */
341 342 343
	spin_lock_init(&dev->clientslock);
	spin_lock_init(&dev->bufferslock);

344
	/* init completion events */
345 346 347 348 349 350 351
	init_completion(&dev->version_ex_done);
	init_completion(&dev->data_download_done);
	init_completion(&dev->trigger_done);
	init_completion(&dev->init_device_done);
	init_completion(&dev->reload_start_done);
	init_completion(&dev->resume_done);

352
	/* alloc common buffer */
353
	dev->common_buffer_size = params->buffer_size * params->num_buffers;
354 355 356 357
	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
						&dev->common_buffer_phys,
						GFP_KERNEL | GFP_DMA);
	if (!dev->common_buffer) {
358 359 360 361
		smscore_unregister_device(dev);
		return -ENOMEM;
	}

362 363 364
	/* prepare dma buffers */
	for (buffer = dev->common_buffer;
	     dev->num_buffers < params->num_buffers;
365
	     dev->num_buffers++, buffer += params->buffer_size) {
366
		struct smscore_buffer_t *cb =
367 368
			smscore_createbuffer(buffer, dev->common_buffer,
					     dev->common_buffer_phys);
369
		if (!cb) {
370 371 372 373 374 375 376
			smscore_unregister_device(dev);
			return -ENOMEM;
		}

		smscore_putbuffer(dev, cb);
	}

377
	sms_info("allocated %d buffers", dev->num_buffers);
378 379 380 381 382 383 384 385 386 387 388 389 390

	dev->mode = DEVICE_MODE_NONE;
	dev->context = params->context;
	dev->device = params->device;
	dev->setmode_handler = params->setmode_handler;
	dev->detectmode_handler = params->detectmode_handler;
	dev->sendrequest_handler = params->sendrequest_handler;
	dev->preload_handler = params->preload_handler;
	dev->postload_handler = params->postload_handler;

	dev->device_flags = params->flags;
	strcpy(dev->devpath, params->devpath);

391
	smscore_registry_settype(dev->devpath, params->device_type);
392

393
	/* add device to devices list */
394 395 396 397 398 399
	kmutex_lock(&g_smscore_deviceslock);
	list_add(&dev->entry, &g_smscore_devices);
	kmutex_unlock(&g_smscore_deviceslock);

	*coredev = dev;

400
	sms_info("device %p created", dev);
401 402 403

	return 0;
}
404
EXPORT_SYMBOL_GPL(smscore_register_device);
405 406 407 408

/**
 * sets initial device mode and notifies client hotplugs that device is ready
 *
409 410
 * @param coredev pointer to a coredev object returned by
 * 		  smscore_register_device
411 412 413
 *
 * @return 0 on success, <0 on error.
 */
414
int smscore_start_device(struct smscore_device_t *coredev)
415
{
416 417
	int rc = smscore_set_device_mode(
			coredev, smscore_registry_getmode(coredev->devpath));
418
	if (rc < 0) {
419
		sms_info("set device mode faile , rc %d", rc);
420
		return rc;
421
	}
422 423 424 425 426

	kmutex_lock(&g_smscore_deviceslock);

	rc = smscore_notify_callbacks(coredev, coredev->device, 1);

427
	sms_info("device %p started, rc %d", coredev, rc);
428 429 430 431 432

	kmutex_unlock(&g_smscore_deviceslock);

	return rc;
}
433
EXPORT_SYMBOL_GPL(smscore_start_device);
434

435 436 437
static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
					void *buffer, size_t size,
					struct completion *completion)
438 439
{
	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
440
	if (rc < 0) {
441
		sms_info("sendrequest returned error %d", rc);
442
		return rc;
443
	}
444

445 446 447
	return wait_for_completion_timeout(completion,
					   msecs_to_jiffies(10000)) ?
						0 : -ETIME;
448 449
}

450 451
static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
					 void *buffer, size_t size)
452
{
453 454
	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
	struct SmsMsgHdr_ST *msg;
455
	u32 mem_address = firmware->StartAddress;
456
	u8 *payload = firmware->Payload;
457 458
	int rc = 0;

459 460
	sms_info("loading FW to addr 0x%x size %d",
		 mem_address, firmware->Length);
461
	if (coredev->preload_handler) {
462 463 464 465 466
		rc = coredev->preload_handler(coredev->context);
		if (rc < 0)
			return rc;
	}

467
	/* PAGE_SIZE buffer shall be enough and dma aligned */
468
	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
469 470 471
	if (!msg)
		return -ENOMEM;

472
	if (coredev->mode != DEVICE_MODE_NONE) {
473
		sms_debug("sending reload command.");
474
		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
475
			     sizeof(struct SmsMsgHdr_ST));
476 477 478
		rc = smscore_sendrequest_and_wait(coredev, msg,
						  msg->msgLength,
						  &coredev->reload_start_done);
479
		mem_address = *(u32 *) &payload[20];
480 481
	}

482
	while (size && rc >= 0) {
483 484
		struct SmsDataDownload_ST *DataMsg =
			(struct SmsDataDownload_ST *) msg;
485 486
		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);

487
		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
488
			     (u16)(sizeof(struct SmsMsgHdr_ST) +
489
				      sizeof(u32) + payload_size));
490 491 492 493

		DataMsg->MemAddr = mem_address;
		memcpy(DataMsg->Payload, payload, payload_size);

494 495
		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
		    (coredev->mode == DEVICE_MODE_NONE))
496 497 498
			rc = coredev->sendrequest_handler(
				coredev->context, DataMsg,
				DataMsg->xMsgHeader.msgLength);
499
		else
500 501 502 503
			rc = smscore_sendrequest_and_wait(
				coredev, DataMsg,
				DataMsg->xMsgHeader.msgLength,
				&coredev->data_download_done);
504 505 506 507 508 509

		payload += payload_size;
		size -= payload_size;
		mem_address += payload_size;
	}

510 511
	if (rc >= 0) {
		if (coredev->mode == DEVICE_MODE_NONE) {
512 513
			struct SmsMsgData_ST *TriggerMsg =
				(struct SmsMsgData_ST *) msg;
514

515
			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
516
				     sizeof(struct SmsMsgHdr_ST) +
517
				     sizeof(u32) * 5);
518

519 520
			TriggerMsg->msgData[0] = firmware->StartAddress;
						/* Entry point */
521 522 523 524
			TriggerMsg->msgData[1] = 5; /* Priority */
			TriggerMsg->msgData[2] = 0x200; /* Stack size */
			TriggerMsg->msgData[3] = 0; /* Parameter */
			TriggerMsg->msgData[4] = 4; /* Task ID */
525

526
			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
527 528 529
				rc = coredev->sendrequest_handler(
					coredev->context, TriggerMsg,
					TriggerMsg->xMsgHeader.msgLength);
530
				msleep(100);
531
			} else
532 533 534 535
				rc = smscore_sendrequest_and_wait(
					coredev, TriggerMsg,
					TriggerMsg->xMsgHeader.msgLength,
					&coredev->trigger_done);
536 537
		} else {
			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
538
				     sizeof(struct SmsMsgHdr_ST));
539

540 541
			rc = coredev->sendrequest_handler(coredev->context,
							  msg, msg->msgLength);
542
		}
543
		msleep(500);
544 545
	}

546
	sms_debug("rc=%d, postload=%p ", rc,
547
		  coredev->postload_handler);
548 549 550

	kfree(msg);

551
	return ((rc >= 0) && coredev->postload_handler) ?
552 553 554 555 556 557 558
		coredev->postload_handler(coredev->context) :
		rc;
}

/**
 * loads specified firmware into a buffer and calls device loadfirmware_handler
 *
559 560
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
561 562 563 564 565
 * @param filename null-terminated string specifies firmware file name
 * @param loadfirmware_handler device handler that loads firmware
 *
 * @return 0 on success, <0 on error.
 */
566 567 568
static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
					   char *filename,
					   loadfirmware_t loadfirmware_handler)
569 570 571
{
	int rc = -ENOENT;
	const struct firmware *fw;
572
	u8 *fw_buffer;
573

574 575
	if (loadfirmware_handler == NULL && !(coredev->device_flags &
					      SMS_DEVICE_FAMILY2))
576 577 578
		return -EINVAL;

	rc = request_firmware(&fw, filename, coredev->device);
579
	if (rc < 0) {
580
		sms_info("failed to open \"%s\"", filename);
581 582
		return rc;
	}
583
	sms_info("read FW %s, size=%zd", filename, fw->size);
584 585 586
	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
			    GFP_KERNEL | GFP_DMA);
	if (fw_buffer) {
587 588 589
		memcpy(fw_buffer, fw->data, fw->size);

		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
590 591 592 593 594
		      smscore_load_firmware_family2(coredev,
						    fw_buffer,
						    fw->size) :
		      loadfirmware_handler(coredev->context,
					   fw_buffer, fw->size);
595 596

		kfree(fw_buffer);
597
	} else {
598
		sms_info("failed to allocate firmware buffer");
599 600 601 602 603 604 605 606 607
		rc = -ENOMEM;
	}

	release_firmware(fw);

	return rc;
}

/**
608 609
 * notifies all clients registered with the device, notifies hotplugs,
 * frees all buffers and coredev object
610
 *
611 612
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
613 614 615
 *
 * @return 0 on success, <0 on error.
 */
616
void smscore_unregister_device(struct smscore_device_t *coredev)
617
{
618
	struct smscore_buffer_t *cb;
619
	int num_buffers = 0;
620
	int retry = 0;
621 622 623 624 625 626

	kmutex_lock(&g_smscore_deviceslock);

	smscore_notify_clients(coredev);
	smscore_notify_callbacks(coredev, NULL, 0);

627 628
	/* at this point all buffers should be back
	 * onresponse must no longer be called */
629

630 631
	while (1) {
		while ((cb = smscore_getbuffer(coredev))) {
632
			kfree(cb);
633
			num_buffers++;
634 635 636
		}
		if (num_buffers == coredev->num_buffers)
			break;
637
		if (++retry > 10) {
638 639
			sms_info("exiting although "
				 "not all buffers released.");
640 641
			break;
		}
642

643
		sms_info("waiting for %d buffer(s)",
644
			 coredev->num_buffers - num_buffers);
645 646 647
		msleep(100);
	}

648
	sms_info("freed %d buffers", num_buffers);
649 650

	if (coredev->common_buffer)
651 652 653
		dma_free_coherent(NULL, coredev->common_buffer_size,
				  coredev->common_buffer,
				  coredev->common_buffer_phys);
654 655 656 657 658 659

	list_del(&coredev->entry);
	kfree(coredev);

	kmutex_unlock(&g_smscore_deviceslock);

660
	sms_info("device %p destroyed", coredev);
661
}
662
EXPORT_SYMBOL_GPL(smscore_unregister_device);
663

664
static int smscore_detect_mode(struct smscore_device_t *coredev)
665
{
666
	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
667
			       GFP_KERNEL | GFP_DMA);
668 669
	struct SmsMsgHdr_ST *msg =
		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
670 671 672 673 674
	int rc;

	if (!buffer)
		return -ENOMEM;

675 676
	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
		     sizeof(struct SmsMsgHdr_ST));
677

678 679 680
	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
					  &coredev->version_ex_done);
	if (rc == -ETIME) {
681
		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
682

683 684
		if (wait_for_completion_timeout(&coredev->resume_done,
						msecs_to_jiffies(5000))) {
685 686 687
			rc = smscore_sendrequest_and_wait(
				coredev, msg, msg->msgLength,
				&coredev->version_ex_done);
688
			if (rc < 0)
689 690
				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
					"second try, rc %d", rc);
691
		} else
692 693 694 695 696 697 698 699
			rc = -ETIME;
	}

	kfree(buffer);

	return rc;
}

700
static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
701 702 703 704 705 706
	/*Stellar		NOVA A0		Nova B0		VEGA*/
	/*DVBT*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	/*DVBH*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	/*TDMB*/
707
	{"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
708 709 710 711 712 713 714 715 716 717
	/*DABIP*/
	{"none", "none", "none", "none"},
	/*BDA*/
	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
	/*ISDBT*/
	{"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
	/*ISDBTBDA*/
	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
	/*CMMB*/
	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
718 719
};

720 721 722 723 724 725
static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
				    int mode, enum sms_device_type_st type)
{
	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
}
726

727 728 729 730
/**
 * calls device handler to change mode of operation
 * NOTE: stellar/usb may disconnect when changing mode
 *
731 732
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
733 734 735 736
 * @param mode requested mode of operation
 *
 * @return 0 on success, <0 on error.
 */
737
int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
738 739 740
{
	void *buffer;
	int rc = 0;
741
	enum sms_device_type_st type;
742

743
	sms_debug("set device mode to %d", mode);
744 745
	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_RAW_TUNER) {
746
			sms_err("invalid mode specified %d", mode);
747 748 749
			return -EINVAL;
		}

750 751
		smscore_registry_setmode(coredev->devpath, mode);

752
		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
753
			rc = smscore_detect_mode(coredev);
754
			if (rc < 0) {
755
				sms_err("mode detect failed %d", rc);
756
				return rc;
757
			}
758
		}
759

760
		if (coredev->mode == mode) {
761
			sms_info("device mode %d already set", mode);
762 763 764
			return 0;
		}

765
		if (!(coredev->modes_supported & (1 << mode))) {
766 767
			char *fw_filename;

768
			type = smscore_registry_gettype(coredev->devpath);
769 770 771 772
			fw_filename = sms_get_fw_name(coredev, mode, type);

			rc = smscore_load_firmware_from_file(coredev,
							     fw_filename, NULL);
773
			if (rc < 0) {
774 775 776
				sms_warn("error %d loading firmware: %s, "
					 "trying again with default firmware",
					 rc, fw_filename);
777 778

				/* try again with the default firmware */
779
				fw_filename = smscore_fw_lkup[mode][type];
780
				rc = smscore_load_firmware_from_file(coredev,
781
							     fw_filename, NULL);
782 783

				if (rc < 0) {
784 785 786
					sms_warn("error %d loading "
						 "firmware: %s", rc,
						 fw_filename);
787 788
					return rc;
				}
789
			}
790
			sms_log("firmware download success: %s", fw_filename);
791
		} else
792 793
			sms_info("mode %d supported by running "
				 "firmware", mode);
794

795 796
		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
797
		if (buffer) {
798 799 800
			struct SmsMsgData_ST *msg =
				(struct SmsMsgData_ST *)
					SMS_ALIGN_ADDRESS(buffer);
801

802
			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
803
				     sizeof(struct SmsMsgData_ST));
804 805
			msg->msgData[0] = mode;

806 807 808
			rc = smscore_sendrequest_and_wait(
				coredev, msg, msg->xMsgHeader.msgLength,
				&coredev->init_device_done);
809 810

			kfree(buffer);
811
		} else {
812 813
			sms_err("Could not allocate buffer for "
				"init device message.");
814
			rc = -ENOMEM;
815 816 817
		}
	} else {
		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
818
			sms_err("invalid mode specified %d", mode);
819 820 821 822 823
			return -EINVAL;
		}

		smscore_registry_setmode(coredev->devpath, mode);

824
		if (coredev->detectmode_handler)
825 826
			coredev->detectmode_handler(coredev->context,
						    &coredev->mode);
827 828 829 830 831

		if (coredev->mode != mode && coredev->setmode_handler)
			rc = coredev->setmode_handler(coredev->context, mode);
	}

832
	if (rc >= 0) {
833 834 835 836
		coredev->mode = mode;
		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
	}

837
	if (rc != 0)
838
		sms_err("return error code %d.", rc);
839 840 841 842 843 844
	return rc;
}

/**
 * calls device handler to get current mode of operation
 *
845 846
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
847 848 849
 *
 * @return current mode
 */
850
int smscore_get_device_mode(struct smscore_device_t *coredev)
851 852 853
{
	return coredev->mode;
}
854
EXPORT_SYMBOL_GPL(smscore_get_device_mode);
855

856 857 858 859
/**
 * find client by response id & type within the clients list.
 * return client handle or NULL.
 *
860 861
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
862
 * @param data_type client data type (SMS_DONT_CARE for all types)
863
 * @param id client id (SMS_DONT_CARE for all id)
864 865
 *
 */
866 867
static struct
smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
868
				      int data_type, int id)
869
{
870
	struct smscore_client_t *client = NULL;
871 872
	struct list_head *next, *first;
	unsigned long flags;
873
	struct list_head *firstid, *nextid;
874 875 876 877


	spin_lock_irqsave(&coredev->clientslock, flags);
	first = &coredev->clients;
878 879 880
	for (next = first->next;
	     (next != first) && !client;
	     next = next->next) {
881
		firstid = &((struct smscore_client_t *)next)->idlist;
882 883 884
		for (nextid = firstid->next;
		     nextid != firstid;
		     nextid = nextid->next) {
885 886 887 888
			if ((((struct smscore_idlist_t *)nextid)->id == id) &&
			    (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
			    (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
				client = (struct smscore_client_t *) next;
889 890
				break;
			}
891 892 893 894 895 896 897 898 899 900
		}
	}
	spin_unlock_irqrestore(&coredev->clientslock, flags);
	return client;
}

/**
 * find client by response id/type, call clients onresponse handler
 * return buffer to pool on error
 *
901 902
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
903 904 905
 * @param cb pointer to response buffer descriptor
 *
 */
906 907
void smscore_onresponse(struct smscore_device_t *coredev,
			struct smscore_buffer_t *cb)
908
{
909 910 911
	struct SmsMsgHdr_ST *phdr =
		(struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
	struct smscore_client_t *client =
912
		smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
913 914
	int rc = -EBUSY;

915 916
	static unsigned long last_sample_time; /* = 0; */
	static int data_total; /* = 0; */
917 918 919 920 921
	unsigned long time_now = jiffies_to_msecs(jiffies);

	if (!last_sample_time)
		last_sample_time = time_now;

922
	if (time_now - last_sample_time > 10000) {
923
		sms_debug("\ndata rate %d bytes/secs",
924 925
			  (int)((data_total * 1000) /
				(time_now - last_sample_time)));
926 927 928 929 930 931

		last_sample_time = time_now;
		data_total = 0;
	}

	data_total += cb->size;
932 933
	/* If no client registered for type & id,
	 * check for control client where type is not registered */
934 935 936
	if (client)
		rc = client->onresponse_handler(client->context, cb);

937 938 939
	if (rc < 0) {
		switch (phdr->msgType) {
		case MSG_SMS_GET_VERSION_EX_RES:
940
		{
941 942
			struct SmsVersionRes_ST *ver =
				(struct SmsVersionRes_ST *) phdr;
943 944
			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
				  "id %d prots 0x%x ver %d.%d",
945 946
				  ver->FirmwareId, ver->SupportedProtocols,
				  ver->RomVersionMajor, ver->RomVersionMinor);
947

948 949 950
			coredev->mode = ver->FirmwareId == 255 ?
				DEVICE_MODE_NONE : ver->FirmwareId;
			coredev->modes_supported = ver->SupportedProtocols;
951

952 953 954 955
			complete(&coredev->version_ex_done);
			break;
		}
		case MSG_SMS_INIT_DEVICE_RES:
956
			sms_debug("MSG_SMS_INIT_DEVICE_RES");
957 958 959
			complete(&coredev->init_device_done);
			break;
		case MSG_SW_RELOAD_START_RES:
960
			sms_debug("MSG_SW_RELOAD_START_RES");
961 962 963 964 965 966
			complete(&coredev->reload_start_done);
			break;
		case MSG_SMS_DATA_DOWNLOAD_RES:
			complete(&coredev->data_download_done);
			break;
		case MSG_SW_RELOAD_EXEC_RES:
967
			sms_debug("MSG_SW_RELOAD_EXEC_RES");
968 969
			break;
		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
970
			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
971 972 973 974 975 976 977
			complete(&coredev->trigger_done);
			break;
		case MSG_SMS_SLEEP_RESUME_COMP_IND:
			complete(&coredev->resume_done);
			break;
		default:
			break;
978 979 980 981
		}
		smscore_putbuffer(coredev, cb);
	}
}
982
EXPORT_SYMBOL_GPL(smscore_onresponse);
983 984 985 986

/**
 * return pointer to next free buffer descriptor from core pool
 *
987 988
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
989 990 991
 *
 * @return pointer to descriptor on success, NULL on error.
 */
992
struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
993
{
994
	struct smscore_buffer_t *cb = NULL;
995 996 997 998
	unsigned long flags;

	spin_lock_irqsave(&coredev->bufferslock, flags);

999
	if (!list_empty(&coredev->buffers)) {
1000
		cb = (struct smscore_buffer_t *) coredev->buffers.next;
1001 1002 1003 1004 1005 1006 1007
		list_del(&cb->entry);
	}

	spin_unlock_irqrestore(&coredev->bufferslock, flags);

	return cb;
}
1008
EXPORT_SYMBOL_GPL(smscore_getbuffer);
1009 1010 1011 1012

/**
 * return buffer descriptor to a pool
 *
1013 1014
 * @param coredev pointer to a coredev object returned by
 *                smscore_register_device
1015 1016 1017
 * @param cb pointer buffer descriptor
 *
 */
1018 1019
void smscore_putbuffer(struct smscore_device_t *coredev,
		       struct smscore_buffer_t *cb)
1020 1021 1022
{
	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
}
1023
EXPORT_SYMBOL_GPL(smscore_putbuffer);
1024

1025 1026 1027
static int smscore_validate_client(struct smscore_device_t *coredev,
				   struct smscore_client_t *client,
				   int data_type, int id)
1028
{
1029 1030
	struct smscore_idlist_t *listentry;
	struct smscore_client_t *registered_client;
1031

1032
	if (!client) {
1033
		sms_err("bad parameter.");
1034 1035 1036
		return -EFAULT;
	}
	registered_client = smscore_find_client(coredev, data_type, id);
1037
	if (registered_client == client)
1038
		return 0;
1039

1040
	if (registered_client) {
1041
		sms_err("The msg ID already registered to another client.");
1042 1043
		return -EEXIST;
	}
1044
	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1045
	if (!listentry) {
1046
		sms_err("Can't allocate memory for client id.");
1047
		return -ENOMEM;
1048 1049 1050
	}
	listentry->id = id;
	listentry->data_type = data_type;
1051 1052
	list_add_locked(&listentry->entry, &client->idlist,
			&coredev->clientslock);
1053 1054 1055 1056 1057 1058 1059 1060 1061
	return 0;
}

/**
 * creates smsclient object, check that id is taken by another client
 *
 * @param coredev pointer to a coredev object from clients hotplug
 * @param initial_id all messages with this id would be sent to this client
 * @param data_type all messages of this type would be sent to this client
1062 1063
 * @param onresponse_handler client handler that is called to
 *                           process incoming messages
1064 1065 1066 1067 1068 1069
 * @param onremove_handler client handler that is called when device is removed
 * @param context client-specific context
 * @param client pointer to a value that receives created smsclient object
 *
 * @return 0 on success, <0 on error.
 */
1070 1071 1072
int smscore_register_client(struct smscore_device_t *coredev,
			    struct smsclient_params_t *params,
			    struct smscore_client_t **client)
1073
{
1074
	struct smscore_client_t *newclient;
1075 1076 1077
	/* check that no other channel with same parameters exists */
	if (smscore_find_client(coredev, params->data_type,
				params->initial_id)) {
1078
		sms_err("Client already exist.");
1079
		return -EEXIST;
1080
	}
1081

1082
	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1083
	if (!newclient) {
1084
		sms_err("Failed to allocate memory for client.");
1085
		return -ENOMEM;
1086 1087
	}

1088
	INIT_LIST_HEAD(&newclient->idlist);
1089 1090 1091 1092
	newclient->coredev = coredev;
	newclient->onresponse_handler = params->onresponse_handler;
	newclient->onremove_handler = params->onremove_handler;
	newclient->context = params->context;
1093 1094 1095 1096
	list_add_locked(&newclient->entry, &coredev->clients,
			&coredev->clientslock);
	smscore_validate_client(coredev, newclient, params->data_type,
				params->initial_id);
1097
	*client = newclient;
1098 1099
	sms_debug("%p %d %d", params->context, params->data_type,
		  params->initial_id);
1100 1101 1102

	return 0;
}
1103
EXPORT_SYMBOL_GPL(smscore_register_client);
1104 1105 1106 1107

/**
 * frees smsclient object and all subclients associated with it
 *
1108 1109
 * @param client pointer to smsclient object returned by
 *               smscore_register_client
1110 1111
 *
 */
1112
void smscore_unregister_client(struct smscore_client_t *client)
1113
{
1114
	struct smscore_device_t *coredev = client->coredev;
1115 1116 1117 1118 1119
	unsigned long flags;

	spin_lock_irqsave(&coredev->clientslock, flags);


1120
	while (!list_empty(&client->idlist)) {
1121 1122
		struct smscore_idlist_t *identry =
			(struct smscore_idlist_t *) client->idlist.next;
1123 1124
		list_del(&identry->entry);
		kfree(identry);
1125 1126
	}

1127
	sms_info("%p", client->context);
1128 1129 1130 1131 1132 1133

	list_del(&client->entry);
	kfree(client);

	spin_unlock_irqrestore(&coredev->clientslock, flags);
}
1134
EXPORT_SYMBOL_GPL(smscore_unregister_client);
1135 1136 1137 1138 1139

/**
 * verifies that source id is not taken by another client,
 * calls device handler to send requests to the device
 *
1140 1141
 * @param client pointer to smsclient object returned by
 *               smscore_register_client
1142 1143 1144 1145 1146
 * @param buffer pointer to a request buffer
 * @param size size (in bytes) of request buffer
 *
 * @return 0 on success, <0 on error.
 */
1147 1148
int smsclient_sendrequest(struct smscore_client_t *client,
			  void *buffer, size_t size)
1149
{
1150 1151
	struct smscore_device_t *coredev;
	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1152 1153
	int rc;

1154
	if (client == NULL) {
1155
		sms_err("Got NULL client");
1156 1157 1158 1159
		return -EINVAL;
	}

	coredev = client->coredev;
1160

1161 1162
	/* check that no other channel with same id exists */
	if (coredev == NULL) {
1163
		sms_err("Got NULL coredev");
1164 1165 1166
		return -EINVAL;
	}

1167 1168
	rc = smscore_validate_client(client->coredev, client, 0,
				     phdr->msgSrcId);
1169 1170 1171 1172 1173
	if (rc < 0)
		return rc;

	return coredev->sendrequest_handler(coredev->context, buffer, size);
}
1174
EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1175 1176


1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
			   struct smscore_gpio_config *pinconfig)
{
	struct {
		struct SmsMsgHdr_ST hdr;
		u32 data[6];
	} msg;

	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
		msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
		msg.hdr.msgDstId = HIF_TASK;
		msg.hdr.msgFlags = 0;
		msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
		msg.hdr.msgLength = sizeof(msg);

		msg.data[0] = pin;
		msg.data[1] = pinconfig->pullupdown;

		/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
		msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;

		switch (pinconfig->outputdriving) {
		case SMS_GPIO_OUTPUTDRIVING_16mA:
			msg.data[3] = 7; /* Nova - 16mA */
			break;
		case SMS_GPIO_OUTPUTDRIVING_12mA:
			msg.data[3] = 5; /* Nova - 11mA */
			break;
		case SMS_GPIO_OUTPUTDRIVING_8mA:
			msg.data[3] = 3; /* Nova - 7mA */
			break;
		case SMS_GPIO_OUTPUTDRIVING_4mA:
		default:
			msg.data[3] = 2; /* Nova - 4mA */
			break;
		}

		msg.data[4] = pinconfig->direction;
		msg.data[5] = 0;
	} else /* TODO: SMS_DEVICE_FAMILY1 */
		return -EINVAL;

	return coredev->sendrequest_handler(coredev->context,
					    &msg, sizeof(msg));
}

int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
{
	struct {
		struct SmsMsgHdr_ST hdr;
		u32 data[3];
	} msg;

	if (pin > MAX_GPIO_PIN_NUMBER)
		return -EINVAL;

	msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
	msg.hdr.msgDstId = HIF_TASK;
	msg.hdr.msgFlags = 0;
	msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
	msg.hdr.msgLength = sizeof(msg);

	msg.data[0] = pin;
	msg.data[1] = level ? 1 : 0;
	msg.data[2] = 0;

	return coredev->sendrequest_handler(coredev->context,
					    &msg, sizeof(msg));
}

1247
static int __init smscore_module_init(void)
1248
{
1249
	int rc = 0;
1250 1251 1252 1253 1254 1255 1256 1257

	INIT_LIST_HEAD(&g_smscore_notifyees);
	INIT_LIST_HEAD(&g_smscore_devices);
	kmutex_init(&g_smscore_deviceslock);

	INIT_LIST_HEAD(&g_smscore_registry);
	kmutex_init(&g_smscore_registrylock);

1258 1259


1260 1261 1262 1263



	return rc;
1264
	sms_debug("rc %d", rc);
1265 1266 1267 1268

	return rc;
}

1269
static void __exit smscore_module_exit(void)
1270
{
1271

1272 1273 1274 1275




1276
	kmutex_lock(&g_smscore_deviceslock);
1277
	while (!list_empty(&g_smscore_notifyees)) {
1278 1279 1280
		struct smscore_device_notifyee_t *notifyee =
			(struct smscore_device_notifyee_t *)
				g_smscore_notifyees.next;
1281 1282 1283 1284 1285 1286 1287

		list_del(&notifyee->entry);
		kfree(notifyee);
	}
	kmutex_unlock(&g_smscore_deviceslock);

	kmutex_lock(&g_smscore_registrylock);
1288
	while (!list_empty(&g_smscore_registry)) {
1289 1290 1291
		struct smscore_registry_entry_t *entry =
			(struct smscore_registry_entry_t *)
				g_smscore_registry.next;
1292 1293 1294 1295 1296 1297

		list_del(&entry->entry);
		kfree(entry);
	}
	kmutex_unlock(&g_smscore_registrylock);

1298
	sms_debug("");
1299 1300 1301 1302 1303
}

module_init(smscore_module_init);
module_exit(smscore_module_exit);

1304 1305
MODULE_DESCRIPTION("Siano MDTV Core module");
MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1306
MODULE_LICENSE("GPL");