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