• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/media/dvb/siano/
1/*
2 *  Siano core API module
3 *
4 *  This file contains implementation for the interface to sms core component
5 *
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 *  Software distributed under the License is distributed on an "AS IS"
15 *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
16 *
17 *  See the GNU General Public License for more details.
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
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 <linux/io.h>
31#include <linux/slab.h>
32
33#include <linux/firmware.h>
34#include <linux/wait.h>
35#include <asm/byteorder.h>
36
37#include "smscoreapi.h"
38#include "sms-cards.h"
39#include "smsir.h"
40#include "smsendian.h"
41
42static int sms_dbg;
43module_param_named(debug, sms_dbg, int, 0644);
44MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
45
46struct smscore_device_notifyee_t {
47	struct list_head entry;
48	hotplug_t hotplug;
49};
50
51struct smscore_idlist_t {
52	struct list_head entry;
53	int		id;
54	int		data_type;
55};
56
57struct smscore_client_t {
58	struct list_head entry;
59	struct smscore_device_t *coredev;
60	void			*context;
61	struct list_head 	idlist;
62	onresponse_t	onresponse_handler;
63	onremove_t		onremove_handler;
64};
65
66void smscore_set_board_id(struct smscore_device_t *core, int id)
67{
68	core->board_id = id;
69}
70
71int smscore_led_state(struct smscore_device_t *core, int led)
72{
73	if (led >= 0)
74		core->led_state = led;
75	return core->led_state;
76}
77EXPORT_SYMBOL_GPL(smscore_set_board_id);
78
79int smscore_get_board_id(struct smscore_device_t *core)
80{
81	return core->board_id;
82}
83EXPORT_SYMBOL_GPL(smscore_get_board_id);
84
85struct smscore_registry_entry_t {
86	struct list_head entry;
87	char			devpath[32];
88	int				mode;
89	enum sms_device_type_st	type;
90};
91
92static struct list_head g_smscore_notifyees;
93static struct list_head g_smscore_devices;
94static struct mutex g_smscore_deviceslock;
95
96static struct list_head g_smscore_registry;
97static struct mutex g_smscore_registrylock;
98
99static int default_mode = 4;
100
101module_param(default_mode, int, 0644);
102MODULE_PARM_DESC(default_mode, "default firmware id (device mode)");
103
104static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
105{
106	struct smscore_registry_entry_t *entry;
107	struct list_head *next;
108
109	kmutex_lock(&g_smscore_registrylock);
110	for (next = g_smscore_registry.next;
111	     next != &g_smscore_registry;
112	     next = next->next) {
113		entry = (struct smscore_registry_entry_t *) next;
114		if (!strcmp(entry->devpath, devpath)) {
115			kmutex_unlock(&g_smscore_registrylock);
116			return entry;
117		}
118	}
119	entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
120	if (entry) {
121		entry->mode = default_mode;
122		strcpy(entry->devpath, devpath);
123		list_add(&entry->entry, &g_smscore_registry);
124	} else
125		sms_err("failed to create smscore_registry.");
126	kmutex_unlock(&g_smscore_registrylock);
127	return entry;
128}
129
130int smscore_registry_getmode(char *devpath)
131{
132	struct smscore_registry_entry_t *entry;
133
134	entry = smscore_find_registry(devpath);
135	if (entry)
136		return entry->mode;
137	else
138		sms_err("No registry found.");
139
140	return default_mode;
141}
142EXPORT_SYMBOL_GPL(smscore_registry_getmode);
143
144static enum sms_device_type_st smscore_registry_gettype(char *devpath)
145{
146	struct smscore_registry_entry_t *entry;
147
148	entry = smscore_find_registry(devpath);
149	if (entry)
150		return entry->type;
151	else
152		sms_err("No registry found.");
153
154	return -1;
155}
156
157void smscore_registry_setmode(char *devpath, int mode)
158{
159	struct smscore_registry_entry_t *entry;
160
161	entry = smscore_find_registry(devpath);
162	if (entry)
163		entry->mode = mode;
164	else
165		sms_err("No registry found.");
166}
167
168static void smscore_registry_settype(char *devpath,
169				     enum sms_device_type_st type)
170{
171	struct smscore_registry_entry_t *entry;
172
173	entry = smscore_find_registry(devpath);
174	if (entry)
175		entry->type = type;
176	else
177		sms_err("No registry found.");
178}
179
180
181static void list_add_locked(struct list_head *new, struct list_head *head,
182			    spinlock_t *lock)
183{
184	unsigned long flags;
185
186	spin_lock_irqsave(lock, flags);
187
188	list_add(new, head);
189
190	spin_unlock_irqrestore(lock, flags);
191}
192
193/**
194 * register a client callback that called when device plugged in/unplugged
195 * NOTE: if devices exist callback is called immediately for each device
196 *
197 * @param hotplug callback
198 *
199 * @return 0 on success, <0 on error.
200 */
201int smscore_register_hotplug(hotplug_t hotplug)
202{
203	struct smscore_device_notifyee_t *notifyee;
204	struct list_head *next, *first;
205	int rc = 0;
206
207	kmutex_lock(&g_smscore_deviceslock);
208
209	notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
210			   GFP_KERNEL);
211	if (notifyee) {
212		/* now notify callback about existing devices */
213		first = &g_smscore_devices;
214		for (next = first->next;
215		     next != first && !rc;
216		     next = next->next) {
217			struct smscore_device_t *coredev =
218				(struct smscore_device_t *) next;
219			rc = hotplug(coredev, coredev->device, 1);
220		}
221
222		if (rc >= 0) {
223			notifyee->hotplug = hotplug;
224			list_add(&notifyee->entry, &g_smscore_notifyees);
225		} else
226			kfree(notifyee);
227	} else
228		rc = -ENOMEM;
229
230	kmutex_unlock(&g_smscore_deviceslock);
231
232	return rc;
233}
234EXPORT_SYMBOL_GPL(smscore_register_hotplug);
235
236/**
237 * unregister a client callback that called when device plugged in/unplugged
238 *
239 * @param hotplug callback
240 *
241 */
242void smscore_unregister_hotplug(hotplug_t hotplug)
243{
244	struct list_head *next, *first;
245
246	kmutex_lock(&g_smscore_deviceslock);
247
248	first = &g_smscore_notifyees;
249
250	for (next = first->next; next != first;) {
251		struct smscore_device_notifyee_t *notifyee =
252			(struct smscore_device_notifyee_t *) next;
253		next = next->next;
254
255		if (notifyee->hotplug == hotplug) {
256			list_del(&notifyee->entry);
257			kfree(notifyee);
258		}
259	}
260
261	kmutex_unlock(&g_smscore_deviceslock);
262}
263EXPORT_SYMBOL_GPL(smscore_unregister_hotplug);
264
265static void smscore_notify_clients(struct smscore_device_t *coredev)
266{
267	struct smscore_client_t *client;
268
269	/* the client must call smscore_unregister_client from remove handler */
270	while (!list_empty(&coredev->clients)) {
271		client = (struct smscore_client_t *) coredev->clients.next;
272		client->onremove_handler(client->context);
273	}
274}
275
276static int smscore_notify_callbacks(struct smscore_device_t *coredev,
277				    struct device *device, int arrival)
278{
279	struct list_head *next, *first;
280	int rc = 0;
281
282	/* note: must be called under g_deviceslock */
283
284	first = &g_smscore_notifyees;
285
286	for (next = first->next; next != first; next = next->next) {
287		rc = ((struct smscore_device_notifyee_t *) next)->
288				hotplug(coredev, device, arrival);
289		if (rc < 0)
290			break;
291	}
292
293	return rc;
294}
295
296static struct
297smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
298				       dma_addr_t common_buffer_phys)
299{
300	struct smscore_buffer_t *cb =
301		kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
302	if (!cb) {
303		sms_info("kmalloc(...) failed");
304		return NULL;
305	}
306
307	cb->p = buffer;
308	cb->offset_in_common = buffer - (u8 *) common_buffer;
309	cb->phys = common_buffer_phys + cb->offset_in_common;
310
311	return cb;
312}
313
314/**
315 * creates coredev object for a device, prepares buffers,
316 * creates buffer mappings, notifies registered hotplugs about new device.
317 *
318 * @param params device pointer to struct with device specific parameters
319 *               and handlers
320 * @param coredev pointer to a value that receives created coredev object
321 *
322 * @return 0 on success, <0 on error.
323 */
324int smscore_register_device(struct smsdevice_params_t *params,
325			    struct smscore_device_t **coredev)
326{
327	struct smscore_device_t *dev;
328	u8 *buffer;
329
330	dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
331	if (!dev) {
332		sms_info("kzalloc(...) failed");
333		return -ENOMEM;
334	}
335
336	/* init list entry so it could be safe in smscore_unregister_device */
337	INIT_LIST_HEAD(&dev->entry);
338
339	/* init queues */
340	INIT_LIST_HEAD(&dev->clients);
341	INIT_LIST_HEAD(&dev->buffers);
342
343	/* init locks */
344	spin_lock_init(&dev->clientslock);
345	spin_lock_init(&dev->bufferslock);
346
347	/* init completion events */
348	init_completion(&dev->version_ex_done);
349	init_completion(&dev->data_download_done);
350	init_completion(&dev->trigger_done);
351	init_completion(&dev->init_device_done);
352	init_completion(&dev->reload_start_done);
353	init_completion(&dev->resume_done);
354	init_completion(&dev->gpio_configuration_done);
355	init_completion(&dev->gpio_set_level_done);
356	init_completion(&dev->gpio_get_level_done);
357	init_completion(&dev->ir_init_done);
358
359	/* Buffer management */
360	init_waitqueue_head(&dev->buffer_mng_waitq);
361
362	/* alloc common buffer */
363	dev->common_buffer_size = params->buffer_size * params->num_buffers;
364	dev->common_buffer = dma_alloc_coherent(NULL, dev->common_buffer_size,
365						&dev->common_buffer_phys,
366						GFP_KERNEL | GFP_DMA);
367	if (!dev->common_buffer) {
368		smscore_unregister_device(dev);
369		return -ENOMEM;
370	}
371
372	/* prepare dma buffers */
373	for (buffer = dev->common_buffer;
374	     dev->num_buffers < params->num_buffers;
375	     dev->num_buffers++, buffer += params->buffer_size) {
376		struct smscore_buffer_t *cb =
377			smscore_createbuffer(buffer, dev->common_buffer,
378					     dev->common_buffer_phys);
379		if (!cb) {
380			smscore_unregister_device(dev);
381			return -ENOMEM;
382		}
383
384		smscore_putbuffer(dev, cb);
385	}
386
387	sms_info("allocated %d buffers", dev->num_buffers);
388
389	dev->mode = DEVICE_MODE_NONE;
390	dev->context = params->context;
391	dev->device = params->device;
392	dev->setmode_handler = params->setmode_handler;
393	dev->detectmode_handler = params->detectmode_handler;
394	dev->sendrequest_handler = params->sendrequest_handler;
395	dev->preload_handler = params->preload_handler;
396	dev->postload_handler = params->postload_handler;
397
398	dev->device_flags = params->flags;
399	strcpy(dev->devpath, params->devpath);
400
401	smscore_registry_settype(dev->devpath, params->device_type);
402
403	/* add device to devices list */
404	kmutex_lock(&g_smscore_deviceslock);
405	list_add(&dev->entry, &g_smscore_devices);
406	kmutex_unlock(&g_smscore_deviceslock);
407
408	*coredev = dev;
409
410	sms_info("device %p created", dev);
411
412	return 0;
413}
414EXPORT_SYMBOL_GPL(smscore_register_device);
415
416
417static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
418		void *buffer, size_t size, struct completion *completion) {
419	int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
420	if (rc < 0) {
421		sms_info("sendrequest returned error %d", rc);
422		return rc;
423	}
424
425	return wait_for_completion_timeout(completion,
426			msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
427			0 : -ETIME;
428}
429
430/**
431 * Starts & enables IR operations
432 *
433 * @return 0 on success, < 0 on error.
434 */
435static int smscore_init_ir(struct smscore_device_t *coredev)
436{
437	int ir_io;
438	int rc;
439	void *buffer;
440
441	coredev->ir.input_dev = NULL;
442	ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
443	if (ir_io) {/* only if IR port exist we use IR sub-module */
444		sms_info("IR loading");
445		rc = sms_ir_init(coredev);
446
447		if	(rc != 0)
448			sms_err("Error initialization DTV IR sub-module");
449		else {
450			buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
451						SMS_DMA_ALIGNMENT,
452						GFP_KERNEL | GFP_DMA);
453			if (buffer) {
454				struct SmsMsgData_ST2 *msg =
455				(struct SmsMsgData_ST2 *)
456				SMS_ALIGN_ADDRESS(buffer);
457
458				SMS_INIT_MSG(&msg->xMsgHeader,
459						MSG_SMS_START_IR_REQ,
460						sizeof(struct SmsMsgData_ST2));
461				msg->msgData[0] = coredev->ir.controller;
462				msg->msgData[1] = coredev->ir.timeout;
463
464				smsendian_handle_tx_message(
465					(struct SmsMsgHdr_ST2 *)msg);
466				rc = smscore_sendrequest_and_wait(coredev, msg,
467						msg->xMsgHeader. msgLength,
468						&coredev->ir_init_done);
469
470				kfree(buffer);
471			} else
472				sms_err
473				("Sending IR initialization message failed");
474		}
475	} else
476		sms_info("IR port has not been detected");
477
478	return 0;
479}
480
481/**
482 * sets initial device mode and notifies client hotplugs that device is ready
483 *
484 * @param coredev pointer to a coredev object returned by
485 * 		  smscore_register_device
486 *
487 * @return 0 on success, <0 on error.
488 */
489int smscore_start_device(struct smscore_device_t *coredev)
490{
491	int rc = smscore_set_device_mode(
492			coredev, smscore_registry_getmode(coredev->devpath));
493	if (rc < 0) {
494		sms_info("set device mode faile , rc %d", rc);
495		return rc;
496	}
497
498	kmutex_lock(&g_smscore_deviceslock);
499
500	rc = smscore_notify_callbacks(coredev, coredev->device, 1);
501	smscore_init_ir(coredev);
502
503	sms_info("device %p started, rc %d", coredev, rc);
504
505	kmutex_unlock(&g_smscore_deviceslock);
506
507	return rc;
508}
509EXPORT_SYMBOL_GPL(smscore_start_device);
510
511
512static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
513					 void *buffer, size_t size)
514{
515	struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
516	struct SmsMsgHdr_ST *msg;
517	u32 mem_address;
518	u8 *payload = firmware->Payload;
519	int rc = 0;
520	firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
521	firmware->Length = le32_to_cpu(firmware->Length);
522
523	mem_address = firmware->StartAddress;
524
525	sms_info("loading FW to addr 0x%x size %d",
526		 mem_address, firmware->Length);
527	if (coredev->preload_handler) {
528		rc = coredev->preload_handler(coredev->context);
529		if (rc < 0)
530			return rc;
531	}
532
533	/* PAGE_SIZE buffer shall be enough and dma aligned */
534	msg = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
535	if (!msg)
536		return -ENOMEM;
537
538	if (coredev->mode != DEVICE_MODE_NONE) {
539		sms_debug("sending reload command.");
540		SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ,
541			     sizeof(struct SmsMsgHdr_ST));
542		rc = smscore_sendrequest_and_wait(coredev, msg,
543						  msg->msgLength,
544						  &coredev->reload_start_done);
545		mem_address = *(u32 *) &payload[20];
546	}
547
548	while (size && rc >= 0) {
549		struct SmsDataDownload_ST *DataMsg =
550			(struct SmsDataDownload_ST *) msg;
551		int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE);
552
553		SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ,
554			     (u16)(sizeof(struct SmsMsgHdr_ST) +
555				      sizeof(u32) + payload_size));
556
557		DataMsg->MemAddr = mem_address;
558		memcpy(DataMsg->Payload, payload, payload_size);
559
560		if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) &&
561		    (coredev->mode == DEVICE_MODE_NONE))
562			rc = coredev->sendrequest_handler(
563				coredev->context, DataMsg,
564				DataMsg->xMsgHeader.msgLength);
565		else
566			rc = smscore_sendrequest_and_wait(
567				coredev, DataMsg,
568				DataMsg->xMsgHeader.msgLength,
569				&coredev->data_download_done);
570
571		payload += payload_size;
572		size -= payload_size;
573		mem_address += payload_size;
574	}
575
576	if (rc >= 0) {
577		if (coredev->mode == DEVICE_MODE_NONE) {
578			struct SmsMsgData_ST *TriggerMsg =
579				(struct SmsMsgData_ST *) msg;
580
581			SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ,
582				     sizeof(struct SmsMsgHdr_ST) +
583				     sizeof(u32) * 5);
584
585			TriggerMsg->msgData[0] = firmware->StartAddress;
586						/* Entry point */
587			TriggerMsg->msgData[1] = 5; /* Priority */
588			TriggerMsg->msgData[2] = 0x200; /* Stack size */
589			TriggerMsg->msgData[3] = 0; /* Parameter */
590			TriggerMsg->msgData[4] = 4; /* Task ID */
591
592			if (coredev->device_flags & SMS_ROM_NO_RESPONSE) {
593				rc = coredev->sendrequest_handler(
594					coredev->context, TriggerMsg,
595					TriggerMsg->xMsgHeader.msgLength);
596				msleep(100);
597			} else
598				rc = smscore_sendrequest_and_wait(
599					coredev, TriggerMsg,
600					TriggerMsg->xMsgHeader.msgLength,
601					&coredev->trigger_done);
602		} else {
603			SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ,
604				     sizeof(struct SmsMsgHdr_ST));
605
606			rc = coredev->sendrequest_handler(coredev->context,
607							  msg, msg->msgLength);
608		}
609		msleep(500);
610	}
611
612	sms_debug("rc=%d, postload=%p ", rc,
613		  coredev->postload_handler);
614
615	kfree(msg);
616
617	return ((rc >= 0) && coredev->postload_handler) ?
618		coredev->postload_handler(coredev->context) :
619		rc;
620}
621
622/**
623 * loads specified firmware into a buffer and calls device loadfirmware_handler
624 *
625 * @param coredev pointer to a coredev object returned by
626 *                smscore_register_device
627 * @param filename null-terminated string specifies firmware file name
628 * @param loadfirmware_handler device handler that loads firmware
629 *
630 * @return 0 on success, <0 on error.
631 */
632static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
633					   char *filename,
634					   loadfirmware_t loadfirmware_handler)
635{
636	int rc = -ENOENT;
637	const struct firmware *fw;
638	u8 *fw_buffer;
639
640	if (loadfirmware_handler == NULL && !(coredev->device_flags &
641					      SMS_DEVICE_FAMILY2))
642		return -EINVAL;
643
644	rc = request_firmware(&fw, filename, coredev->device);
645	if (rc < 0) {
646		sms_info("failed to open \"%s\"", filename);
647		return rc;
648	}
649	sms_info("read FW %s, size=%zd", filename, fw->size);
650	fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT),
651			    GFP_KERNEL | GFP_DMA);
652	if (fw_buffer) {
653		memcpy(fw_buffer, fw->data, fw->size);
654
655		rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ?
656		      smscore_load_firmware_family2(coredev,
657						    fw_buffer,
658						    fw->size) :
659		      loadfirmware_handler(coredev->context,
660					   fw_buffer, fw->size);
661
662		kfree(fw_buffer);
663	} else {
664		sms_info("failed to allocate firmware buffer");
665		rc = -ENOMEM;
666	}
667
668	release_firmware(fw);
669
670	return rc;
671}
672
673/**
674 * notifies all clients registered with the device, notifies hotplugs,
675 * frees all buffers and coredev object
676 *
677 * @param coredev pointer to a coredev object returned by
678 *                smscore_register_device
679 *
680 * @return 0 on success, <0 on error.
681 */
682void smscore_unregister_device(struct smscore_device_t *coredev)
683{
684	struct smscore_buffer_t *cb;
685	int num_buffers = 0;
686	int retry = 0;
687
688	kmutex_lock(&g_smscore_deviceslock);
689
690	/* Release input device (IR) resources */
691	sms_ir_exit(coredev);
692
693	smscore_notify_clients(coredev);
694	smscore_notify_callbacks(coredev, NULL, 0);
695
696	/* at this point all buffers should be back
697	 * onresponse must no longer be called */
698
699	while (1) {
700		while (!list_empty(&coredev->buffers)) {
701			cb = (struct smscore_buffer_t *) coredev->buffers.next;
702			list_del(&cb->entry);
703			kfree(cb);
704			num_buffers++;
705		}
706		if (num_buffers == coredev->num_buffers)
707			break;
708		if (++retry > 10) {
709			sms_info("exiting although "
710				 "not all buffers released.");
711			break;
712		}
713
714		sms_info("waiting for %d buffer(s)",
715			 coredev->num_buffers - num_buffers);
716		msleep(100);
717	}
718
719	sms_info("freed %d buffers", num_buffers);
720
721	if (coredev->common_buffer)
722		dma_free_coherent(NULL, coredev->common_buffer_size,
723			coredev->common_buffer, coredev->common_buffer_phys);
724
725	if (coredev->fw_buf != NULL)
726		kfree(coredev->fw_buf);
727
728	list_del(&coredev->entry);
729	kfree(coredev);
730
731	kmutex_unlock(&g_smscore_deviceslock);
732
733	sms_info("device %p destroyed", coredev);
734}
735EXPORT_SYMBOL_GPL(smscore_unregister_device);
736
737static int smscore_detect_mode(struct smscore_device_t *coredev)
738{
739	void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT,
740			       GFP_KERNEL | GFP_DMA);
741	struct SmsMsgHdr_ST *msg =
742		(struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer);
743	int rc;
744
745	if (!buffer)
746		return -ENOMEM;
747
748	SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ,
749		     sizeof(struct SmsMsgHdr_ST));
750
751	rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength,
752					  &coredev->version_ex_done);
753	if (rc == -ETIME) {
754		sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try");
755
756		if (wait_for_completion_timeout(&coredev->resume_done,
757						msecs_to_jiffies(5000))) {
758			rc = smscore_sendrequest_and_wait(
759				coredev, msg, msg->msgLength,
760				&coredev->version_ex_done);
761			if (rc < 0)
762				sms_err("MSG_SMS_GET_VERSION_EX_REQ failed "
763					"second try, rc %d", rc);
764		} else
765			rc = -ETIME;
766	}
767
768	kfree(buffer);
769
770	return rc;
771}
772
773static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
774	/*Stellar		NOVA A0		Nova B0		VEGA*/
775	/*DVBT*/
776	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
777	/*DVBH*/
778	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
779	/*TDMB*/
780	{"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"},
781	/*DABIP*/
782	{"none", "none", "none", "none"},
783	/*BDA*/
784	{"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
785	/*ISDBT*/
786	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
787	/*ISDBTBDA*/
788	{"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
789	/*CMMB*/
790	{"none", "none", "none", "cmmb_vega_12mhz.inp"}
791};
792
793static inline char *sms_get_fw_name(struct smscore_device_t *coredev,
794				    int mode, enum sms_device_type_st type)
795{
796	char **fw = sms_get_board(smscore_get_board_id(coredev))->fw;
797	return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type];
798}
799
800/**
801 * calls device handler to change mode of operation
802 * NOTE: stellar/usb may disconnect when changing mode
803 *
804 * @param coredev pointer to a coredev object returned by
805 *                smscore_register_device
806 * @param mode requested mode of operation
807 *
808 * @return 0 on success, <0 on error.
809 */
810int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
811{
812	void *buffer;
813	int rc = 0;
814	enum sms_device_type_st type;
815
816	sms_debug("set device mode to %d", mode);
817	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
818		if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) {
819			sms_err("invalid mode specified %d", mode);
820			return -EINVAL;
821		}
822
823		smscore_registry_setmode(coredev->devpath, mode);
824
825		if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) {
826			rc = smscore_detect_mode(coredev);
827			if (rc < 0) {
828				sms_err("mode detect failed %d", rc);
829				return rc;
830			}
831		}
832
833		if (coredev->mode == mode) {
834			sms_info("device mode %d already set", mode);
835			return 0;
836		}
837
838		if (!(coredev->modes_supported & (1 << mode))) {
839			char *fw_filename;
840
841			type = smscore_registry_gettype(coredev->devpath);
842			fw_filename = sms_get_fw_name(coredev, mode, type);
843
844			rc = smscore_load_firmware_from_file(coredev,
845							     fw_filename, NULL);
846			if (rc < 0) {
847				sms_warn("error %d loading firmware: %s, "
848					 "trying again with default firmware",
849					 rc, fw_filename);
850
851				/* try again with the default firmware */
852				fw_filename = smscore_fw_lkup[mode][type];
853				rc = smscore_load_firmware_from_file(coredev,
854							     fw_filename, NULL);
855
856				if (rc < 0) {
857					sms_warn("error %d loading "
858						 "firmware: %s", rc,
859						 fw_filename);
860					return rc;
861				}
862			}
863			sms_log("firmware download success: %s", fw_filename);
864		} else
865			sms_info("mode %d supported by running "
866				 "firmware", mode);
867
868		buffer = kmalloc(sizeof(struct SmsMsgData_ST) +
869				 SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
870		if (buffer) {
871			struct SmsMsgData_ST *msg =
872				(struct SmsMsgData_ST *)
873					SMS_ALIGN_ADDRESS(buffer);
874
875			SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ,
876				     sizeof(struct SmsMsgData_ST));
877			msg->msgData[0] = mode;
878
879			rc = smscore_sendrequest_and_wait(
880				coredev, msg, msg->xMsgHeader.msgLength,
881				&coredev->init_device_done);
882
883			kfree(buffer);
884		} else {
885			sms_err("Could not allocate buffer for "
886				"init device message.");
887			rc = -ENOMEM;
888		}
889	} else {
890		if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) {
891			sms_err("invalid mode specified %d", mode);
892			return -EINVAL;
893		}
894
895		smscore_registry_setmode(coredev->devpath, mode);
896
897		if (coredev->detectmode_handler)
898			coredev->detectmode_handler(coredev->context,
899						    &coredev->mode);
900
901		if (coredev->mode != mode && coredev->setmode_handler)
902			rc = coredev->setmode_handler(coredev->context, mode);
903	}
904
905	if (rc >= 0) {
906		coredev->mode = mode;
907		coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
908	}
909
910	if (rc < 0)
911		sms_err("return error code %d.", rc);
912	return rc;
913}
914
915/**
916 * calls device handler to get current mode of operation
917 *
918 * @param coredev pointer to a coredev object returned by
919 *                smscore_register_device
920 *
921 * @return current mode
922 */
923int smscore_get_device_mode(struct smscore_device_t *coredev)
924{
925	return coredev->mode;
926}
927EXPORT_SYMBOL_GPL(smscore_get_device_mode);
928
929/**
930 * find client by response id & type within the clients list.
931 * return client handle or NULL.
932 *
933 * @param coredev pointer to a coredev object returned by
934 *                smscore_register_device
935 * @param data_type client data type (SMS_DONT_CARE for all types)
936 * @param id client id (SMS_DONT_CARE for all id)
937 *
938 */
939static struct
940smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
941				      int data_type, int id)
942{
943	struct smscore_client_t *client = NULL;
944	struct list_head *next, *first;
945	unsigned long flags;
946	struct list_head *firstid, *nextid;
947
948
949	spin_lock_irqsave(&coredev->clientslock, flags);
950	first = &coredev->clients;
951	for (next = first->next;
952	     (next != first) && !client;
953	     next = next->next) {
954		firstid = &((struct smscore_client_t *)next)->idlist;
955		for (nextid = firstid->next;
956		     nextid != firstid;
957		     nextid = nextid->next) {
958			if ((((struct smscore_idlist_t *)nextid)->id == id) &&
959			    (((struct smscore_idlist_t *)nextid)->data_type == data_type ||
960			    (((struct smscore_idlist_t *)nextid)->data_type == 0))) {
961				client = (struct smscore_client_t *) next;
962				break;
963			}
964		}
965	}
966	spin_unlock_irqrestore(&coredev->clientslock, flags);
967	return client;
968}
969
970/**
971 * find client by response id/type, call clients onresponse handler
972 * return buffer to pool on error
973 *
974 * @param coredev pointer to a coredev object returned by
975 *                smscore_register_device
976 * @param cb pointer to response buffer descriptor
977 *
978 */
979void smscore_onresponse(struct smscore_device_t *coredev,
980		struct smscore_buffer_t *cb) {
981	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
982			+ cb->offset);
983	struct smscore_client_t *client;
984	int rc = -EBUSY;
985	static unsigned long last_sample_time; /* = 0; */
986	static int data_total; /* = 0; */
987	unsigned long time_now = jiffies_to_msecs(jiffies);
988
989	if (!last_sample_time)
990		last_sample_time = time_now;
991
992	if (time_now - last_sample_time > 10000) {
993		sms_debug("\ndata rate %d bytes/secs",
994			  (int)((data_total * 1000) /
995				(time_now - last_sample_time)));
996
997		last_sample_time = time_now;
998		data_total = 0;
999	}
1000
1001	data_total += cb->size;
1002	/* Do we need to re-route? */
1003	if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
1004			(phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
1005		if (coredev->mode == DEVICE_MODE_DVBT_BDA)
1006			phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
1007	}
1008
1009
1010	client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
1011
1012	/* If no client registered for type & id,
1013	 * check for control client where type is not registered */
1014	if (client)
1015		rc = client->onresponse_handler(client->context, cb);
1016
1017	if (rc < 0) {
1018		switch (phdr->msgType) {
1019		case MSG_SMS_GET_VERSION_EX_RES:
1020		{
1021			struct SmsVersionRes_ST *ver =
1022				(struct SmsVersionRes_ST *) phdr;
1023			sms_debug("MSG_SMS_GET_VERSION_EX_RES "
1024				  "id %d prots 0x%x ver %d.%d",
1025				  ver->FirmwareId, ver->SupportedProtocols,
1026				  ver->RomVersionMajor, ver->RomVersionMinor);
1027
1028			coredev->mode = ver->FirmwareId == 255 ?
1029				DEVICE_MODE_NONE : ver->FirmwareId;
1030			coredev->modes_supported = ver->SupportedProtocols;
1031
1032			complete(&coredev->version_ex_done);
1033			break;
1034		}
1035		case MSG_SMS_INIT_DEVICE_RES:
1036			sms_debug("MSG_SMS_INIT_DEVICE_RES");
1037			complete(&coredev->init_device_done);
1038			break;
1039		case MSG_SW_RELOAD_START_RES:
1040			sms_debug("MSG_SW_RELOAD_START_RES");
1041			complete(&coredev->reload_start_done);
1042			break;
1043		case MSG_SMS_DATA_DOWNLOAD_RES:
1044			complete(&coredev->data_download_done);
1045			break;
1046		case MSG_SW_RELOAD_EXEC_RES:
1047			sms_debug("MSG_SW_RELOAD_EXEC_RES");
1048			break;
1049		case MSG_SMS_SWDOWNLOAD_TRIGGER_RES:
1050			sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES");
1051			complete(&coredev->trigger_done);
1052			break;
1053		case MSG_SMS_SLEEP_RESUME_COMP_IND:
1054			complete(&coredev->resume_done);
1055			break;
1056		case MSG_SMS_GPIO_CONFIG_EX_RES:
1057			sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
1058			complete(&coredev->gpio_configuration_done);
1059			break;
1060		case MSG_SMS_GPIO_SET_LEVEL_RES:
1061			sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
1062			complete(&coredev->gpio_set_level_done);
1063			break;
1064		case MSG_SMS_GPIO_GET_LEVEL_RES:
1065		{
1066			u32 *msgdata = (u32 *) phdr;
1067			coredev->gpio_get_res = msgdata[1];
1068			sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
1069					coredev->gpio_get_res);
1070			complete(&coredev->gpio_get_level_done);
1071			break;
1072		}
1073		case MSG_SMS_START_IR_RES:
1074			complete(&coredev->ir_init_done);
1075			break;
1076		case MSG_SMS_IR_SAMPLES_IND:
1077			sms_ir_event(coredev,
1078				(const char *)
1079				((char *)phdr
1080				+ sizeof(struct SmsMsgHdr_ST)),
1081				(int)phdr->msgLength
1082				- sizeof(struct SmsMsgHdr_ST));
1083			break;
1084
1085		default:
1086			break;
1087		}
1088		smscore_putbuffer(coredev, cb);
1089	}
1090}
1091EXPORT_SYMBOL_GPL(smscore_onresponse);
1092
1093/**
1094 * return pointer to next free buffer descriptor from core pool
1095 *
1096 * @param coredev pointer to a coredev object returned by
1097 *                smscore_register_device
1098 *
1099 * @return pointer to descriptor on success, NULL on error.
1100 */
1101
1102struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
1103{
1104	struct smscore_buffer_t *cb = NULL;
1105	unsigned long flags;
1106
1107	spin_lock_irqsave(&coredev->bufferslock, flags);
1108	if (!list_empty(&coredev->buffers)) {
1109		cb = (struct smscore_buffer_t *) coredev->buffers.next;
1110		list_del(&cb->entry);
1111	}
1112	spin_unlock_irqrestore(&coredev->bufferslock, flags);
1113	return cb;
1114}
1115
1116struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
1117{
1118	struct smscore_buffer_t *cb = NULL;
1119
1120	wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
1121
1122	return cb;
1123}
1124EXPORT_SYMBOL_GPL(smscore_getbuffer);
1125
1126/**
1127 * return buffer descriptor to a pool
1128 *
1129 * @param coredev pointer to a coredev object returned by
1130 *                smscore_register_device
1131 * @param cb pointer buffer descriptor
1132 *
1133 */
1134void smscore_putbuffer(struct smscore_device_t *coredev,
1135		struct smscore_buffer_t *cb) {
1136	wake_up_interruptible(&coredev->buffer_mng_waitq);
1137	list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
1138}
1139EXPORT_SYMBOL_GPL(smscore_putbuffer);
1140
1141static int smscore_validate_client(struct smscore_device_t *coredev,
1142				   struct smscore_client_t *client,
1143				   int data_type, int id)
1144{
1145	struct smscore_idlist_t *listentry;
1146	struct smscore_client_t *registered_client;
1147
1148	if (!client) {
1149		sms_err("bad parameter.");
1150		return -EFAULT;
1151	}
1152	registered_client = smscore_find_client(coredev, data_type, id);
1153	if (registered_client == client)
1154		return 0;
1155
1156	if (registered_client) {
1157		sms_err("The msg ID already registered to another client.");
1158		return -EEXIST;
1159	}
1160	listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
1161	if (!listentry) {
1162		sms_err("Can't allocate memory for client id.");
1163		return -ENOMEM;
1164	}
1165	listentry->id = id;
1166	listentry->data_type = data_type;
1167	list_add_locked(&listentry->entry, &client->idlist,
1168			&coredev->clientslock);
1169	return 0;
1170}
1171
1172/**
1173 * creates smsclient object, check that id is taken by another client
1174 *
1175 * @param coredev pointer to a coredev object from clients hotplug
1176 * @param initial_id all messages with this id would be sent to this client
1177 * @param data_type all messages of this type would be sent to this client
1178 * @param onresponse_handler client handler that is called to
1179 *                           process incoming messages
1180 * @param onremove_handler client handler that is called when device is removed
1181 * @param context client-specific context
1182 * @param client pointer to a value that receives created smsclient object
1183 *
1184 * @return 0 on success, <0 on error.
1185 */
1186int smscore_register_client(struct smscore_device_t *coredev,
1187			    struct smsclient_params_t *params,
1188			    struct smscore_client_t **client)
1189{
1190	struct smscore_client_t *newclient;
1191	/* check that no other channel with same parameters exists */
1192	if (smscore_find_client(coredev, params->data_type,
1193				params->initial_id)) {
1194		sms_err("Client already exist.");
1195		return -EEXIST;
1196	}
1197
1198	newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
1199	if (!newclient) {
1200		sms_err("Failed to allocate memory for client.");
1201		return -ENOMEM;
1202	}
1203
1204	INIT_LIST_HEAD(&newclient->idlist);
1205	newclient->coredev = coredev;
1206	newclient->onresponse_handler = params->onresponse_handler;
1207	newclient->onremove_handler = params->onremove_handler;
1208	newclient->context = params->context;
1209	list_add_locked(&newclient->entry, &coredev->clients,
1210			&coredev->clientslock);
1211	smscore_validate_client(coredev, newclient, params->data_type,
1212				params->initial_id);
1213	*client = newclient;
1214	sms_debug("%p %d %d", params->context, params->data_type,
1215		  params->initial_id);
1216
1217	return 0;
1218}
1219EXPORT_SYMBOL_GPL(smscore_register_client);
1220
1221/**
1222 * frees smsclient object and all subclients associated with it
1223 *
1224 * @param client pointer to smsclient object returned by
1225 *               smscore_register_client
1226 *
1227 */
1228void smscore_unregister_client(struct smscore_client_t *client)
1229{
1230	struct smscore_device_t *coredev = client->coredev;
1231	unsigned long flags;
1232
1233	spin_lock_irqsave(&coredev->clientslock, flags);
1234
1235
1236	while (!list_empty(&client->idlist)) {
1237		struct smscore_idlist_t *identry =
1238			(struct smscore_idlist_t *) client->idlist.next;
1239		list_del(&identry->entry);
1240		kfree(identry);
1241	}
1242
1243	sms_info("%p", client->context);
1244
1245	list_del(&client->entry);
1246	kfree(client);
1247
1248	spin_unlock_irqrestore(&coredev->clientslock, flags);
1249}
1250EXPORT_SYMBOL_GPL(smscore_unregister_client);
1251
1252/**
1253 * verifies that source id is not taken by another client,
1254 * calls device handler to send requests to the device
1255 *
1256 * @param client pointer to smsclient object returned by
1257 *               smscore_register_client
1258 * @param buffer pointer to a request buffer
1259 * @param size size (in bytes) of request buffer
1260 *
1261 * @return 0 on success, <0 on error.
1262 */
1263int smsclient_sendrequest(struct smscore_client_t *client,
1264			  void *buffer, size_t size)
1265{
1266	struct smscore_device_t *coredev;
1267	struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer;
1268	int rc;
1269
1270	if (client == NULL) {
1271		sms_err("Got NULL client");
1272		return -EINVAL;
1273	}
1274
1275	coredev = client->coredev;
1276
1277	/* check that no other channel with same id exists */
1278	if (coredev == NULL) {
1279		sms_err("Got NULL coredev");
1280		return -EINVAL;
1281	}
1282
1283	rc = smscore_validate_client(client->coredev, client, 0,
1284				     phdr->msgSrcId);
1285	if (rc < 0)
1286		return rc;
1287
1288	return coredev->sendrequest_handler(coredev->context, buffer, size);
1289}
1290EXPORT_SYMBOL_GPL(smsclient_sendrequest);
1291
1292
1293/* old GPIO managements implementation */
1294int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
1295			   struct smscore_config_gpio *pinconfig)
1296{
1297	struct {
1298		struct SmsMsgHdr_ST hdr;
1299		u32 data[6];
1300	} msg;
1301
1302	if (coredev->device_flags & SMS_DEVICE_FAMILY2) {
1303		msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1304		msg.hdr.msgDstId = HIF_TASK;
1305		msg.hdr.msgFlags = 0;
1306		msg.hdr.msgType  = MSG_SMS_GPIO_CONFIG_EX_REQ;
1307		msg.hdr.msgLength = sizeof(msg);
1308
1309		msg.data[0] = pin;
1310		msg.data[1] = pinconfig->pullupdown;
1311
1312		/* Convert slew rate for Nova: Fast(0) = 3 / Slow(1) = 0; */
1313		msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0;
1314
1315		switch (pinconfig->outputdriving) {
1316		case SMS_GPIO_OUTPUTDRIVING_16mA:
1317			msg.data[3] = 7; /* Nova - 16mA */
1318			break;
1319		case SMS_GPIO_OUTPUTDRIVING_12mA:
1320			msg.data[3] = 5; /* Nova - 11mA */
1321			break;
1322		case SMS_GPIO_OUTPUTDRIVING_8mA:
1323			msg.data[3] = 3; /* Nova - 7mA */
1324			break;
1325		case SMS_GPIO_OUTPUTDRIVING_4mA:
1326		default:
1327			msg.data[3] = 2; /* Nova - 4mA */
1328			break;
1329		}
1330
1331		msg.data[4] = pinconfig->direction;
1332		msg.data[5] = 0;
1333	} else /* TODO: SMS_DEVICE_FAMILY1 */
1334		return -EINVAL;
1335
1336	return coredev->sendrequest_handler(coredev->context,
1337					    &msg, sizeof(msg));
1338}
1339
1340int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
1341{
1342	struct {
1343		struct SmsMsgHdr_ST hdr;
1344		u32 data[3];
1345	} msg;
1346
1347	if (pin > MAX_GPIO_PIN_NUMBER)
1348		return -EINVAL;
1349
1350	msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1351	msg.hdr.msgDstId = HIF_TASK;
1352	msg.hdr.msgFlags = 0;
1353	msg.hdr.msgType  = MSG_SMS_GPIO_SET_LEVEL_REQ;
1354	msg.hdr.msgLength = sizeof(msg);
1355
1356	msg.data[0] = pin;
1357	msg.data[1] = level ? 1 : 0;
1358	msg.data[2] = 0;
1359
1360	return coredev->sendrequest_handler(coredev->context,
1361					    &msg, sizeof(msg));
1362}
1363
1364/* new GPIO management implementation */
1365static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
1366		u32 *pGroupNum, u32 *pGroupCfg) {
1367
1368	*pGroupCfg = 1;
1369
1370	if (PinNum <= 1)	{
1371		*pTranslatedPinNum = 0;
1372		*pGroupNum = 9;
1373		*pGroupCfg = 2;
1374	} else if (PinNum >= 2 && PinNum <= 6) {
1375		*pTranslatedPinNum = 2;
1376		*pGroupNum = 0;
1377		*pGroupCfg = 2;
1378	} else if (PinNum >= 7 && PinNum <= 11) {
1379		*pTranslatedPinNum = 7;
1380		*pGroupNum = 1;
1381	} else if (PinNum >= 12 && PinNum <= 15) {
1382		*pTranslatedPinNum = 12;
1383		*pGroupNum = 2;
1384		*pGroupCfg = 3;
1385	} else if (PinNum == 16) {
1386		*pTranslatedPinNum = 16;
1387		*pGroupNum = 23;
1388	} else if (PinNum >= 17 && PinNum <= 24) {
1389		*pTranslatedPinNum = 17;
1390		*pGroupNum = 3;
1391	} else if (PinNum == 25) {
1392		*pTranslatedPinNum = 25;
1393		*pGroupNum = 6;
1394	} else if (PinNum >= 26 && PinNum <= 28) {
1395		*pTranslatedPinNum = 26;
1396		*pGroupNum = 4;
1397	} else if (PinNum == 29) {
1398		*pTranslatedPinNum = 29;
1399		*pGroupNum = 5;
1400		*pGroupCfg = 2;
1401	} else if (PinNum == 30) {
1402		*pTranslatedPinNum = 30;
1403		*pGroupNum = 8;
1404	} else if (PinNum == 31) {
1405		*pTranslatedPinNum = 31;
1406		*pGroupNum = 17;
1407	} else
1408		return -1;
1409
1410	*pGroupCfg <<= 24;
1411
1412	return 0;
1413}
1414
1415int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
1416		struct smscore_gpio_config *pGpioConfig) {
1417
1418	u32 totalLen;
1419	u32 TranslatedPinNum = 0;
1420	u32 GroupNum = 0;
1421	u32 ElectricChar;
1422	u32 groupCfg;
1423	void *buffer;
1424	int rc;
1425
1426	struct SetGpioMsg {
1427		struct SmsMsgHdr_ST xMsgHeader;
1428		u32 msgData[6];
1429	} *pMsg;
1430
1431
1432	if (PinNum > MAX_GPIO_PIN_NUMBER)
1433		return -EINVAL;
1434
1435	if (pGpioConfig == NULL)
1436		return -EINVAL;
1437
1438	totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
1439
1440	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1441			GFP_KERNEL | GFP_DMA);
1442	if (!buffer)
1443		return -ENOMEM;
1444
1445	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1446
1447	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1448	pMsg->xMsgHeader.msgDstId = HIF_TASK;
1449	pMsg->xMsgHeader.msgFlags = 0;
1450	pMsg->xMsgHeader.msgLength = (u16) totalLen;
1451	pMsg->msgData[0] = PinNum;
1452
1453	if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
1454		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
1455		if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
1456				&groupCfg) != 0) {
1457			rc = -EINVAL;
1458			goto free;
1459		}
1460
1461		pMsg->msgData[1] = TranslatedPinNum;
1462		pMsg->msgData[2] = GroupNum;
1463		ElectricChar = (pGpioConfig->PullUpDown)
1464				| (pGpioConfig->InputCharacteristics << 2)
1465				| (pGpioConfig->OutputSlewRate << 3)
1466				| (pGpioConfig->OutputDriving << 4);
1467		pMsg->msgData[3] = ElectricChar;
1468		pMsg->msgData[4] = pGpioConfig->Direction;
1469		pMsg->msgData[5] = groupCfg;
1470	} else {
1471		pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
1472		pMsg->msgData[1] = pGpioConfig->PullUpDown;
1473		pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
1474		pMsg->msgData[3] = pGpioConfig->OutputDriving;
1475		pMsg->msgData[4] = pGpioConfig->Direction;
1476		pMsg->msgData[5] = 0;
1477	}
1478
1479	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1480	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1481			&coredev->gpio_configuration_done);
1482
1483	if (rc != 0) {
1484		if (rc == -ETIME)
1485			sms_err("smscore_gpio_configure timeout");
1486		else
1487			sms_err("smscore_gpio_configure error");
1488	}
1489free:
1490	kfree(buffer);
1491
1492	return rc;
1493}
1494
1495int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
1496		u8 NewLevel) {
1497
1498	u32 totalLen;
1499	int rc;
1500	void *buffer;
1501
1502	struct SetGpioMsg {
1503		struct SmsMsgHdr_ST xMsgHeader;
1504		u32 msgData[3]; /* keep it 3 ! */
1505	} *pMsg;
1506
1507	if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
1508			(PinNum > MAX_GPIO_PIN_NUMBER))
1509		return -EINVAL;
1510
1511	totalLen = sizeof(struct SmsMsgHdr_ST) +
1512			(3 * sizeof(u32)); /* keep it 3 ! */
1513
1514	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1515			GFP_KERNEL | GFP_DMA);
1516	if (!buffer)
1517		return -ENOMEM;
1518
1519	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1520
1521	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1522	pMsg->xMsgHeader.msgDstId = HIF_TASK;
1523	pMsg->xMsgHeader.msgFlags = 0;
1524	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
1525	pMsg->xMsgHeader.msgLength = (u16) totalLen;
1526	pMsg->msgData[0] = PinNum;
1527	pMsg->msgData[1] = NewLevel;
1528
1529	/* Send message to SMS */
1530	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1531	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1532			&coredev->gpio_set_level_done);
1533
1534	if (rc != 0) {
1535		if (rc == -ETIME)
1536			sms_err("smscore_gpio_set_level timeout");
1537		else
1538			sms_err("smscore_gpio_set_level error");
1539	}
1540	kfree(buffer);
1541
1542	return rc;
1543}
1544
1545int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
1546		u8 *level) {
1547
1548	u32 totalLen;
1549	int rc;
1550	void *buffer;
1551
1552	struct SetGpioMsg {
1553		struct SmsMsgHdr_ST xMsgHeader;
1554		u32 msgData[2];
1555	} *pMsg;
1556
1557
1558	if (PinNum > MAX_GPIO_PIN_NUMBER)
1559		return -EINVAL;
1560
1561	totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
1562
1563	buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
1564			GFP_KERNEL | GFP_DMA);
1565	if (!buffer)
1566		return -ENOMEM;
1567
1568	pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
1569
1570	pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
1571	pMsg->xMsgHeader.msgDstId = HIF_TASK;
1572	pMsg->xMsgHeader.msgFlags = 0;
1573	pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
1574	pMsg->xMsgHeader.msgLength = (u16) totalLen;
1575	pMsg->msgData[0] = PinNum;
1576	pMsg->msgData[1] = 0;
1577
1578	/* Send message to SMS */
1579	smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
1580	rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
1581			&coredev->gpio_get_level_done);
1582
1583	if (rc != 0) {
1584		if (rc == -ETIME)
1585			sms_err("smscore_gpio_get_level timeout");
1586		else
1587			sms_err("smscore_gpio_get_level error");
1588	}
1589	kfree(buffer);
1590
1591	/* Its a race between other gpio_get_level() and the copy of the single
1592	 * global 'coredev->gpio_get_res' to  the function's variable 'level'
1593	 */
1594	*level = coredev->gpio_get_res;
1595
1596	return rc;
1597}
1598
1599static int __init smscore_module_init(void)
1600{
1601	int rc = 0;
1602
1603	INIT_LIST_HEAD(&g_smscore_notifyees);
1604	INIT_LIST_HEAD(&g_smscore_devices);
1605	kmutex_init(&g_smscore_deviceslock);
1606
1607	INIT_LIST_HEAD(&g_smscore_registry);
1608	kmutex_init(&g_smscore_registrylock);
1609
1610	return rc;
1611}
1612
1613static void __exit smscore_module_exit(void)
1614{
1615	kmutex_lock(&g_smscore_deviceslock);
1616	while (!list_empty(&g_smscore_notifyees)) {
1617		struct smscore_device_notifyee_t *notifyee =
1618			(struct smscore_device_notifyee_t *)
1619				g_smscore_notifyees.next;
1620
1621		list_del(&notifyee->entry);
1622		kfree(notifyee);
1623	}
1624	kmutex_unlock(&g_smscore_deviceslock);
1625
1626	kmutex_lock(&g_smscore_registrylock);
1627	while (!list_empty(&g_smscore_registry)) {
1628		struct smscore_registry_entry_t *entry =
1629			(struct smscore_registry_entry_t *)
1630				g_smscore_registry.next;
1631
1632		list_del(&entry->entry);
1633		kfree(entry);
1634	}
1635	kmutex_unlock(&g_smscore_registrylock);
1636
1637	sms_debug("");
1638}
1639
1640module_init(smscore_module_init);
1641module_exit(smscore_module_exit);
1642
1643MODULE_DESCRIPTION("Siano MDTV Core module");
1644MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
1645MODULE_LICENSE("GPL");
1646