import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / hdmi / Sii8348 / mhl_linux_tx.c
CommitLineData
6fa3eb70
S
1/*
2
3SiI8348 Linux Driver
4
5Copyright (C) 2013 Silicon Image, Inc.
6
7This program is free software; you can redistribute it and/or
8modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation version 2.
10This program is distributed AS-IS WITHOUT ANY WARRANTY of any
11kind, whether express or implied; INCLUDING without the implied warranty
12of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT. See
13the GNU General Public License for more details at http://www.gnu.org/licenses/gpl-2.0.html.
14
15*/
16#include <linux/module.h>
17
18#include <linux/kernel.h>
19#include <linux/slab.h>
20#include <linux/hrtimer.h>
21#include <linux/fs.h>
22#include <linux/semaphore.h>
23#include <linux/i2c.h>
24#include <linux/interrupt.h>
25#include <linux/cdev.h>
26#include <linux/stringify.h>
27#include <asm/uaccess.h>
28
29#include "sii_hal.h"
30#include "si_fw_macros.h"
31#include "si_mhl_defs.h"
32#include "si_infoframe.h"
33#include "si_edid.h"
34#include "si_mhl2_edid_3d_api.h"
35#include "si_mhl_tx_hw_drv_api.h"
36#ifdef MEDIA_DATA_TUNNEL_SUPPORT
37#include "si_mdt_inputdev.h"
38#endif
39#ifdef RCP_INPUTDEV_SUPPORT
40#include "mhl_rcp_inputdev.h"
41#endif
42#include "mhl_linux_tx.h"
43#include "mhl_supp.h"
44#include "platform.h"
45
46#include <linux/kthread.h>
47#include <mach/irqs.h>
48#include "mach/eint.h"
49#include <mach/mt_gpio.h>
50#include <cust_gpio_usage.h>
51#include <cust_eint.h>
52#include "hdmi_drv.h"
53#include "smartbook.h"
54
55#define MHL_DRIVER_MINOR_MAX 1
56static wait_queue_head_t mhl_irq_wq;
57static struct task_struct *mhl_irq_task = NULL;
58static atomic_t mhl_irq_event = ATOMIC_INIT(0);
59
60
61/************************** MHL TX User Layer To HAL****************************************/
62#ifdef CONFIG_MTK_SMARTBOOK_SUPPORT
63extern int smartbook_kthread(void *data);
64extern wait_queue_head_t smartbook_wq;
65static struct task_struct *smartbook_task = NULL;
66#endif
67
68void Notify_AP_MHL_TX_Event(unsigned int event, unsigned int event_param, void *param);
69/************************** ****************************************************/
70
71
72struct mhl_dev_context *si_dev_context;
73
74
75static char *white_space = "' ', '\t'";
76static dev_t dev_num;
77
78static struct class *mhl_class;
79
80static void mhl_tx_destroy_timer_support(struct mhl_dev_context *dev_context);
81
82/* Define SysFs attribute names */
83#define SYS_ATTR_NAME_CONN connection_state
84#define SYS_ATTR_NAME_RCP rcp_keycode
85#define SYS_ATTR_NAME_RCPK rcp_ack
86#define SYS_ATTR_NAME_RAP rap
87#define SYS_ATTR_NAME_RAP_STATUS rap_status
88#define SYS_ATTR_NAME_DEVCAP devcap
89#define SYS_ATTR_NAME_UCP ucp_keycode
90#define SYS_ATTR_NAME_UCPK ucp_ack
91#define SYS_ATTR_NAME_SPAD spad
92#define SYS_ATTR_NAME_DEBUG debug
93#define SYS_ATTR_NAME_TRACE_LEVEL trace_level
94
95
96/*
97 * show_connection_state() - Handle read request to the connection_state
98 * attribute file.
99 */
100ssize_t show_connection_state(struct device *dev, struct device_attribute *attr, char *buf)
101{
102 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
103
104 if (dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) {
105 return scnprintf(buf, PAGE_SIZE, "connected");
106 } else {
107 return scnprintf(buf, PAGE_SIZE, "not connected");
108 }
109}
110
111#ifndef RCP_INPUTDEV_SUPPORT
112/*
113 * show_rcp() - Handle read request to the rcp_keycode attribute file.
114 */
115ssize_t show_rcp(struct device *dev, struct device_attribute *attr, char *buf)
116{
117 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
118 int status = 0;
119
120 if (down_interruptible(&dev_context->isr_lock))
121 return -ERESTARTSYS;
122
123 if (dev_context->mhl_flags &
124 (MHL_STATE_FLAG_RCP_SENT | MHL_STATE_FLAG_RCP_RECEIVED)) {
125 status = scnprintf(buf, PAGE_SIZE, "0x%02x %s",
126 dev_context->rcp_key_code,
127 dev_context->mhl_flags & MHL_STATE_FLAG_RCP_SENT? "sent" : "received");
128 }
129
130 up(&dev_context->isr_lock);
131
132 return status;
133}
134
135
136/*
137 * send_rcp() - Handle write request to the rcp_keycode attribute file.
138 */
139ssize_t send_rcp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
140{
141 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
142 unsigned long key_code;
143 int status = -EINVAL;
144
145 MHL_TX_DBG_INFO(dev_context, "send_rcp received string: ""%s""\n", buf);
146
147 if (down_interruptible(&dev_context->isr_lock))
148 return -ERESTARTSYS;
149
150 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
151 status = -ENODEV;
152 goto err_exit;
153 }
154
155 if (!(dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED))
156 goto err_exit;
157
158 if (strict_strtoul(buf, 0, &key_code)) {
159 MHL_TX_DBG_ERR(dev_context, "Unable to convert key code string\n");
160 goto err_exit;
161 }
162
163 if (key_code >= 0xFE) {
164 MHL_TX_DBG_ERR(dev_context, "key code (0x%lx) is too large to be valid\n", key_code);
165 goto err_exit;
166 }
167
168 dev_context->mhl_flags &= ~(MHL_STATE_FLAG_RCP_RECEIVED |
169 MHL_STATE_FLAG_RCP_ACK |
170 MHL_STATE_FLAG_RCP_NAK);
171 dev_context->mhl_flags |= MHL_STATE_FLAG_RCP_SENT;
172 dev_context->rcp_send_status = 0;
173 dev_context->rcp_key_code = (u8)key_code;
174 if (!si_mhl_tx_rcp_send(dev_context, (u8)key_code))
175 goto err_exit;
176
177 status = count;
178
179err_exit:
180 up(&dev_context->isr_lock);
181
182 return status;
183}
184
185
186/*
187 * send_rcp_ack() - Handle write request to the rcp_ack attribute file.
188 *
189 * This file is used to send either an ACK or NAK for a received
190 * Remote Control Protocol (RCP) key code.
191 *
192 * The format of the string in buf must be:
193 * "keycode=<keyvalue> errorcode=<errorvalue>
194 * where: <keyvalue> is replaced with value of the RCP to be ACK'd or NAK'd
195 * <errorvalue> 0 if the RCP key code is to be ACK'd
196 * non-zero error code if the RCP key code is to be NAK'd
197 */
198ssize_t send_rcp_ack(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
199{
200 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
201 unsigned long key_code = 0x100; /* initialize with invalid values */
202 unsigned long err_code = 0x100;
203 char *pStr;
204 int status = -EINVAL;
205
206 MHL_TX_DBG_INFO(dev_context, "received string: %s\n", buf);
207
208 /* Parse the input string and extract the RCP key code and error code */
209 pStr = strstr(buf, "keycode=");
210 if (pStr != NULL) {
211 key_code = simple_strtoul(pStr + 8, NULL, 0);
212 if (key_code > 0xFF) {
213 MHL_TX_DBG_ERR(dev_context, "Unable to convert keycode string\n");
214 goto err_exit_2;
215 }
216 } else {
217 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""keycode"" value\n");
218 goto err_exit_2;
219 }
220
221 pStr = strstr(buf, "errorcode=");
222 if (pStr != NULL) {
223 if(strict_strtoul(pStr + 10, 0, &err_code)) {
224 MHL_TX_DBG_ERR(dev_context, "Unable to convert errorcode string\n");
225 goto err_exit_2;
226 }
227 } else {
228 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""errorcode"" value\n");
229 goto err_exit_2;
230 }
231
232 if ((key_code > 0xFF) || (err_code > 0xFF)) {
233 MHL_TX_DBG_ERR(dev_context, "Invalid key code or error code "\
234 "specified, key code: 0x%02lx error code: 0x%02lx\n",
235 key_code, err_code);
236 goto err_exit_2;
237 }
238
239 if (down_interruptible(&dev_context->isr_lock))
240 return -ERESTARTSYS;
241
242 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
243 status = -ENODEV;
244 goto err_exit_1;
245 }
246
247 if (dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) {
248
249 if((key_code != dev_context->rcp_key_code)
250 || !(dev_context->mhl_flags & MHL_STATE_FLAG_RCP_RECEIVED)) {
251
252 MHL_TX_DBG_ERR(dev_context, "Attempting to ACK a key code "\
253 "that was not received! try:0x%02x(%d)\n"
254 ,dev_context->rcp_key_code
255 ,dev_context->rcp_key_code);
256 goto err_exit_1;
257 }
258
259 if (err_code == 0) {
260 if (!si_mhl_tx_rcpk_send(dev_context, (u8)key_code)) {
261 status = -ENOMEM;
262 goto err_exit_1;
263 }
264 } else {
265 if (!si_mhl_tx_rcpe_send(dev_context, (u8)err_code))
266 goto err_exit_1;
267 }
268
269 status = count;
270 }
271
272err_exit_1:
273 up(&dev_context->isr_lock);
274
275err_exit_2:
276 return status;
277}
278
279
280/*
281 * show_rcp_ack() - Handle read request to the rcp_ack attribute file.
282 *
283 * Reads from this file return a string detailing the last RCP
284 * ACK or NAK received by the driver.
285 *
286 * The format of the string returned in buf is:
287 * "keycode=<keyvalue> errorcode=<errorvalue>
288 * where: <keyvalue> is replaced with value of the RCP key code for which
289 * an ACK or NAK has been received.
290 * <errorvalue> 0 if the last RCP key code was ACK'd or
291 * non-zero error code if the RCP key code was NAK'd
292 */
293ssize_t show_rcp_ack(struct device *dev, struct device_attribute *attr, char *buf)
294{
295 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
296 int status = -EINVAL;
297
298 MHL_TX_DBG_INFO(dev_context, "called\n");
299
300 if (down_interruptible(&dev_context->isr_lock))
301 return -ERESTARTSYS;
302
303 if (dev_context->mhl_flags & (MHL_STATE_FLAG_RCP_ACK | MHL_STATE_FLAG_RCP_NAK)) {
304
305 status = scnprintf(buf, PAGE_SIZE, "keycode=0x%02x errorcode=0x%02x",
306 dev_context->rcp_key_code, dev_context->rcp_err_code);
307 }
308
309 up(&dev_context->isr_lock);
310
311 return status;
312}
313#endif /* #ifndef RCP_INPUTDEV_SUPPORT */
314
315/*
316 * show_ucp() - Handle read request to the ucp_keycode attribute file.
317 */
318ssize_t show_ucp(struct device *dev, struct device_attribute *attr, char *buf)
319{
320 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
321 int status = 0;
322
323 MHL_TX_DBG_INFO(dev_context, "called keycode:0x%02x\n",dev_context->ucp_key_code);
324 if (down_interruptible(&dev_context->isr_lock))
325 return -ERESTARTSYS;
326
327 if (dev_context->mhl_flags &
328 (MHL_STATE_FLAG_UCP_SENT | MHL_STATE_FLAG_UCP_RECEIVED)) {
329 status = scnprintf(buf, PAGE_SIZE, "0x%02x %s",
330 dev_context->ucp_key_code,
331 dev_context->mhl_flags & MHL_STATE_FLAG_UCP_SENT? "sent" : "received");
332 }
333
334 up(&dev_context->isr_lock);
335
336 return status;
337}
338
339
340/*
341 * send_ucp() - Handle write request to the ucp_keycode attribute file.
342 */
343ssize_t send_ucp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
344{
345 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
346 unsigned long key_code;
347 int status = -EINVAL;
348
349 MHL_TX_DBG_INFO(dev_context, "received string: ""%s""\n", buf);
350
351 if (down_interruptible(&dev_context->isr_lock))
352 return -ERESTARTSYS;
353
354 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
355 status = -ENODEV;
356 goto err_exit;
357 }
358
359 if (!(dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED))
360 goto err_exit;
361
362 if (strict_strtoul(buf, 0, &key_code)) {
363 MHL_TX_DBG_ERR(dev_context, "Unable to convert key code string\n");
364 goto err_exit;
365 }
366
367 if (key_code > 0xFF) {
368 MHL_TX_DBG_ERR(dev_context, "ucp key code (0x%lx) is too large to be valid\n", key_code);
369 goto err_exit;
370 }
371
372 dev_context->mhl_flags &= ~(MHL_STATE_FLAG_UCP_RECEIVED |
373 MHL_STATE_FLAG_UCP_ACK |
374 MHL_STATE_FLAG_UCP_NAK);
375 dev_context->mhl_flags |= MHL_STATE_FLAG_UCP_SENT;
376 dev_context->ucp_key_code = (u8)key_code;
377 if (!si_mhl_tx_ucp_send(dev_context, (u8)key_code))
378 goto err_exit;
379
380 status = count;
381
382err_exit:
383 up(&dev_context->isr_lock);
384
385 return status;
386}
387
388
389/*
390 * send_ucp_ack() - Handle write request to the ucp_ack attribute file.
391 *
392 * This file is used to send either an ACK or NAK for a received
393 * UTF-8 Control Protocol (UCP) key code.
394 *
395 * The format of the string in buf must be:
396 * "keycode=<keyvalue> errorcode=<errorvalue>
397 * where: <keyvalue> is replaced with value of the UCP to be ACK'd or NAK'd
398 * <errorvalue> 0 if the UCP key code is to be ACK'd
399 * non-zero error code if the UCP key code is to be NAK'd
400 */
401ssize_t send_ucp_ack(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
402{
403 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
404 unsigned long key_code = 0x100; /* initialize with invalid values */
405 unsigned long err_code = 0x100;
406 char *pStr;
407 int status = -EINVAL;
408
409 MHL_TX_DBG_INFO(dev_context, "received string: %s\n", buf);
410
411 /* Parse the input string and extract the UCP key code and error code */
412 pStr = strstr(buf, "keycode=");
413 if (pStr != NULL) {
414 key_code = simple_strtoul(pStr + 8, NULL, 0);
415 if (key_code > 0xFF) {
416 MHL_TX_DBG_ERR(dev_context, "Unable to convert keycode string\n");
417 goto err_exit_2;
418 }
419 } else {
420 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""keycode"" value\n");
421 goto err_exit_2;
422 }
423
424 pStr = strstr(buf, "errorcode=");
425 if (pStr != NULL) {
426 if(strict_strtoul(pStr + 10, 0, &err_code)) {
427 MHL_TX_DBG_ERR(dev_context, "Unable to convert errorcode string\n");
428 goto err_exit_2;
429 }
430 } else {
431 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""errorcode"" value\n");
432 goto err_exit_2;
433 }
434
435 if ((key_code > 0xFF) || (err_code > 0xFF)) {
436 MHL_TX_DBG_ERR(dev_context, "Invalid key code or error code "\
437 "specified, key code: 0x%02lx error code: 0x%02lx\n",
438 key_code, err_code);
439 goto err_exit_2;
440 }
441
442 if (down_interruptible(&dev_context->isr_lock))
443 return -ERESTARTSYS;
444
445 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
446 status = -ENODEV;
447 goto err_exit_1;
448 }
449
450 if (dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) {
451
452 if((key_code != dev_context->ucp_key_code)
453 || !(dev_context->mhl_flags & MHL_STATE_FLAG_UCP_RECEIVED)) {
454
455 MHL_TX_DBG_ERR(dev_context, "Attempting to ACK a key code that was not received!\n");
456 goto err_exit_1;
457 }
458
459 if (err_code == 0) {
460 if (!si_mhl_tx_ucpk_send(dev_context, (u8)key_code)) {
461 status = -ENOMEM;
462 goto err_exit_1;
463 }
464 } else {
465 if (!si_mhl_tx_ucpe_send(dev_context, (u8)err_code)) {
466 status = -ENOMEM;
467 goto err_exit_1;
468 }
469 }
470
471 status = count;
472 }
473
474err_exit_1:
475 up(&dev_context->isr_lock);
476
477err_exit_2:
478 return status;
479}
480
481
482/*
483 * show_ucp_ack() - Handle read request to the ucp_ack attribute file.
484 *
485 * Reads from this file return a string detailing the last UCP
486 * ACK or NAK received by the driver.
487 *
488 * The format of the string returned in buf is:
489 * "keycode=<keyvalue> errorcode=<errorvalue>
490 * where: <keyvalue> is replaced with value of the UCP key code for which
491 * an ACK or NAK has been received.
492 * <errorvalue> 0 if the last UCP key code was ACK'd or
493 * non-zero error code if the UCP key code was NAK'd
494 */
495ssize_t show_ucp_ack(struct device *dev, struct device_attribute *attr,
496 char *buf)
497{
498 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
499 int status = -EINVAL;
500
501 MHL_TX_DBG_INFO(dev_context, "called\n");
502
503 if (down_interruptible(&dev_context->isr_lock))
504 return -ERESTARTSYS;
505
506 if (dev_context->mhl_flags & (MHL_STATE_FLAG_UCP_ACK | MHL_STATE_FLAG_UCP_NAK)) {
507
508 status = scnprintf(buf, PAGE_SIZE, "keycode=0x%02x errorcode=0x%02x",
509 dev_context->ucp_key_code, dev_context->ucp_err_code);
510 }
511
512 up(&dev_context->isr_lock);
513
514 return status;
515}
516
517/*
518 * show_rap() - Handle read request to the rap attribute file.
519 *
520 * Reads from this file return a string value indicating the last
521 * Request Action Protocol (RAP) request received.
522 *
523 * The return value is the number characters written to buf, or EAGAIN
524 * if the driver is busy and cannot service the read request immediately.
525 * If EAGAIN is returned the caller should wait a little and retry the
526 * read.
527 */
528ssize_t show_rap(struct device *dev, struct device_attribute *attr, char *buf)
529{
530 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
531 int status = -EINVAL;
532
533 MHL_TX_DBG_INFO(dev_context, "called last sub-command:0x%02x\n",dev_context->rap_sub_command);
534
535 if (down_interruptible(&dev_context->isr_lock)){
536 MHL_TX_DBG_ERR(dev_context,"-ERESTARTSYS\n");
537 return -ERESTARTSYS;
538 }
539
540 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
541 MHL_TX_DBG_ERR(dev_context,"-ENODEV\n");
542 status = -ENODEV;
543 goto err_exit;
544 }
545 *buf = '\0';
546 if (MHL_RAP_POLL == dev_context->rap_sub_command)
547 status = scnprintf(buf, PAGE_SIZE, "poll");
548 else if (MHL_RAP_CONTENT_ON == dev_context->rap_sub_command)
549 status = scnprintf(buf, PAGE_SIZE, "content_on");
550 else if (MHL_RAP_CONTENT_OFF == dev_context->rap_sub_command)
551 status = scnprintf(buf, PAGE_SIZE, "content_off");
552 MHL_TX_DBG_INFO(dev_context,"buf:%c%s%c\n",'"',buf,'"');
553
554err_exit:
555 up(&dev_context->isr_lock);
556
557 return status;
558}
559
560/*
561 * send_rap() - Handle write request to the rap attribute file.
562 *
563 * Writes to this file cause a RAP message with the specified action code
564 * to be sent to the downstream device.
565 */
566ssize_t send_rap(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
567{
568 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
569 int status;
570
571 /* Assume success */
572 status = count;
573
574 MHL_TX_DBG_INFO(dev_context, "received string: %s\n", buf);
575
576 if (down_interruptible(&dev_context->isr_lock))
577 return -ERESTARTSYS;
578
579 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
580 status = -ENODEV;
581 goto err_exit;
582 }
583
584 if (strnicmp("poll", buf, count - 1) == 0) {
585 if (!si_mhl_tx_rap_send(dev_context, MHL_RAP_POLL))
586 status = -EPERM;
587
588 } else if (strnicmp("content_on", buf, count - 1) == 0) {
589 if (!si_mhl_tx_rap_send(dev_context, MHL_RAP_CONTENT_ON))
590 status = -EPERM;
591
592 } else if (strnicmp("content_off", buf, count - 1) == 0) {
593 if (!si_mhl_tx_rap_send(dev_context, MHL_RAP_CONTENT_OFF))
594 status = -EPERM;
595
596 } else {
597 MHL_TX_DBG_ERR(dev_context, "Invalid parameter %s received\n", buf);
598 status = -EINVAL;
599 }
600
601err_exit:
602 up(&dev_context->isr_lock);
603
604 return status;
605}
606//( begin rap_status interface
607/*
608 * show_rap_status() - Handle read request to the rap_status attribute file.
609 *
610 * Reads from this file return the last setting from the customer application
611 */
612ssize_t show_rap_status(struct device *dev, struct device_attribute *attr, char *buf)
613{
614 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
615 int status = -EINVAL;
616
617
618 MHL_TX_DBG_INFO(dev_context, "called last sub-command:0x%02x\n",dev_context->rap_sub_command);
619
620 if (down_interruptible(&dev_context->isr_lock)){
621 MHL_TX_DBG_ERR(dev_context,"-ERESTARTSYS\n");
622 return -ERESTARTSYS;
623 }
624
625 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
626 MHL_TX_DBG_ERR(dev_context,"-ENODEV\n");
627 status = -ENODEV;
628 goto err_exit;
629 }
630 *buf = '\0';
631 if (dev_context->mhl_flags & MHL_STATE_APPLICATION_RAP_BUSY){
632 status = scnprintf(buf, PAGE_SIZE, "busy");
633 }else{
634 status = scnprintf(buf, PAGE_SIZE, "ready");
635 }
636 MHL_TX_DBG_INFO(dev_context,"buf:%c%s%c\n",'"',buf,'"');
637
638err_exit:
639 up(&dev_context->isr_lock);
640
641 return status;
642}
643
644/*
645 * set_rap_status() - Handle write request to the rap attribute file.
646 *
647 * Writes to this file cause a RAP message with the specified action code
648 * to be sent to the downstream device.
649 */
650ssize_t set_rap_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
651{
652 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
653 int status;
654
655 /* Assume success */
656 status = count;
657
658 MHL_TX_DBG_INFO(dev_context, "received string: %s\n", buf);
659
660 if (down_interruptible(&dev_context->isr_lock))
661 return -ERESTARTSYS;
662
663 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
664 status = -ENODEV;
665 goto err_exit;
666 }
667
668 if (strnicmp("busy", buf, count - 1) == 0) {
669 dev_context->mhl_flags |= MHL_STATE_APPLICATION_RAP_BUSY;
670 } else if (strnicmp("ready", buf, count - 1) == 0) {
671 dev_context->mhl_flags &= ~MHL_STATE_APPLICATION_RAP_BUSY;
672 } else {
673 MHL_TX_DBG_ERR(dev_context, "Invalid parameter %s received\n", buf);
674 status = -EINVAL;
675 }
676
677err_exit:
678 up(&dev_context->isr_lock);
679
680 return status;
681}
682
683//) end rap_status interface
684
685/*
686 * select_dev_cap() - Handle write request to the devcap attribute file.
687 *
688 * Writes to the devcap file are done to set the offset of a particular
689 * Device Capabilities register to be returned by a subsequent read
690 * from this file.
691 *
692 * All we need to do is validate the specified offset and if valid
693 * save it for later use.
694 */
695ssize_t select_dev_cap(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
696{
697 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
698 unsigned long offset;
699 int status = -EINVAL;
700
701
702 MHL_TX_DBG_INFO(dev_context, "received string: ""%s""\n", buf);
703
704 if (strict_strtoul(buf, 0, &offset)) {
705 MHL_TX_DBG_ERR(dev_context, "Unable to convert register offset string\n");
706 goto err_exit;
707 }
708
709 if (offset > 0x0F) {
710 MHL_TX_DBG_INFO(dev_context,
711 "dev cap offset (0x%lx) is too large to be valid\n", offset);
712 goto err_exit;
713 }
714
715 dev_context->dev_cap_offset = (u8)offset;
716 status = count;
717
718err_exit:
719 return status;
720}
721
722
723/*
724 * show_dev_cap() - Handle read request to the devcap attribute file.
725 *
726 * Reads from this file return the hexadecimal string value of the last
727 * Device Capability register offset written to this file.
728 *
729 * The return value is the number characters written to buf, or EAGAIN
730 * if the driver is busy and cannot service the read request immediately.
731 * If EAGAIN is returned the caller should wait a little and retry the
732 * read.
733 *
734 * The format of the string returned in buf is:
735 * "offset:<offset>=<regvalue>
736 * where: <offset> is the last Device Capability register offset
737 * written to this file
738 * <regvalue> the currentl value of the Device Capability register
739 * specified in offset
740 */
741ssize_t show_dev_cap(struct device *dev, struct device_attribute *attr, char *buf)
742{
743 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
744 uint8_t regValue;
745 int status = -EINVAL;
746
747
748 MHL_TX_DBG_INFO(dev_context, "called\n");
749
750 if (down_interruptible(&dev_context->isr_lock))
751 return -ERESTARTSYS;
752
753 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
754 status = -ENODEV;
755 goto err_exit;
756 }
757
758 if (dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) {
759
760 status = si_mhl_tx_get_peer_dev_cap_entry(dev_context,
761 dev_context->dev_cap_offset,
762 &regValue);
763 if (status != 0) {
764 /*
765 * Driver is busy and cannot provide the requested DEVCAP
766 * register value right now so inform caller they need to
767 * try again later.
768 */
769 status = -EAGAIN;
770 goto err_exit;
771 }
772 status = scnprintf(buf, PAGE_SIZE, "offset:0x%02x=0x%02x",
773 dev_context->dev_cap_offset, regValue);
774 }
775
776err_exit:
777 up(&dev_context->isr_lock);
778
779 return status;
780}
781
782
783/*
784 * send_scratch_pad() - Handle write request to the spad attribute file.
785 *
786 * This file is used to either initiate a write to the scratch pad registers
787 * of an attached device, or to set the offset and byte count for a subsequent
788 * read from the local scratch pad registers.
789 *
790 * The format of the string in buf must be:
791 * offset=<offset_value> length=<Length_value> \
792 * data=data_byte_0 ... data_byte_length-1
793 * where: <offset_value> specifies the starting register offset to begin
794 * read/writing within the scratch pad register space
795 * <length_value> number of scratch pad registers to be written/read
796 * data_byte space separated list of <length_value> data bytes
797 * to be written. If no data bytes are present then
798 * the write to this file will only be used to set
799 * the offset and length for a subsequent read from
800 * this file.
801 */
802ssize_t send_scratch_pad(struct device *dev, struct device_attribute *attr,
803 const char *buf, size_t count)
804{
805 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
806 unsigned long offset = 0x100; /* initialize with invalid values */
807 unsigned long length = 0x100;
808 unsigned long value;
809 u8 data[MAX_SCRATCH_PAD_TRANSFER_SIZE];
810 u8 idx;
811 char *str;
812 char *endptr;
813 enum scratch_pad_status scratch_pad_status;
814 int status = -EINVAL;
815
816 MHL_TX_DBG_ERR(dev_context, "received string: ""%s""\n", buf);
817
818 /*
819 * Parse the input string and extract the scratch pad register selection
820 * parameters
821 */
822 str = strstr(buf, "offset=");
823 if (str != NULL) {
824 offset = simple_strtoul(str + 7, NULL, 0);
825 if (offset > SCRATCH_PAD_SIZE) {
826 MHL_TX_DBG_ERR(dev_context, "Invalid offset value entered\n");
827 goto err_exit_2;
828 }
829 } else {
830 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""offset"" value\n");
831 goto err_exit_2;
832 }
833
834 str = strstr(buf, "length=");
835 if (str != NULL) {
836 length = simple_strtoul(str + 7, NULL, 0);
837 if (length > MAX_SCRATCH_PAD_TRANSFER_SIZE) {
838 MHL_TX_DBG_ERR(dev_context, "Transfer length too large\n");
839 goto err_exit_2;
840 }
841 } else {
842 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""length"" value\n");
843 goto err_exit_2;
844 }
845
846 str = strstr(buf, "data=");
847 if (str != NULL) {
848
849 str += 5;
850 endptr = str;
851 for(idx = 0; idx < length; idx++) {
852
853 endptr += strspn(endptr, white_space);
854 str = endptr;
855 if (*str == 0) {
856 MHL_TX_DBG_ERR(dev_context, "Too few data values provided\n");
857 goto err_exit_2;
858 }
859
860 value = simple_strtoul(str, &endptr, 0);
861 if (value > 0xFF) {
862 MHL_TX_DBG_ERR(dev_context, "Invalid scratch pad data detected\n");
863 goto err_exit_2;
864 }
865
866 data[idx] = value;
867 }
868
869 } else {
870 idx = 0;
871 }
872
873 if ((offset + length) > SCRATCH_PAD_SIZE) {
874 MHL_TX_DBG_ERR(dev_context, "Invalid offset/length combination entered");
875 goto err_exit_2;
876 }
877
878 dev_context->spad_offset = offset;
879 dev_context->spad_xfer_length = length;
880
881 if (idx == 0) {
882 MHL_TX_DBG_INFO(dev_context, "No data specified, storing offset "\
883 "and length for subsequent scratch pad read\n");
884
885 goto err_exit_2;
886 }
887
888 if (down_interruptible(&dev_context->isr_lock))
889 return -ERESTARTSYS;
890
891 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
892 status = -ENODEV;
893 goto err_exit_1;
894 }
895
896 /*
897 * Make sure there is an MHL connection and that the requested
898 * data transfer parameters don't exceed the address space of
899 * the scratch pad. NOTE: The address space reserved for the
900 * Scratch Pad registers is 64 bytes but sources and sink devices
901 * are only required to implement the 1st 16 bytes.
902 */
903 if (!(dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) ||
904 (length < ADOPTER_ID_SIZE) ||
905 (offset > (SCRATCH_PAD_SIZE - ADOPTER_ID_SIZE)) ||
906 (offset + length > SCRATCH_PAD_SIZE)) {
907 status = -EINVAL;
908 goto err_exit_1;
909 }
910
911 dev_context->mhl_flags |= MHL_STATE_FLAG_SPAD_SENT;
912 dev_context->spad_send_status = 0;
913
914 scratch_pad_status = si_mhl_tx_request_write_burst(dev_context, offset, length, data);
915
916 switch (scratch_pad_status) {
917 case SCRATCHPAD_SUCCESS:
918 /* On success return the number of bytes written to this file */
919 status = count;
920 break;
921
922 case SCRATCHPAD_BUSY:
923 status = -EAGAIN;
924 break;
925
926 default:
927 status = -EFAULT;
928 break;
929 }
930
931err_exit_1:
932 up(&dev_context->isr_lock);
933
934err_exit_2:
935 return status;
936}
937
938
939/*
940 * show_scratch_pad() - Handle read request to the spad attribute file.
941 *
942 * Reads from this file return one or more scratch pad register values
943 * in hexadecimal string format. The registers returned are specified
944 * by the offset and length values previously written to this file.
945 *
946 * The return value is the number characters written to buf, or EAGAIN
947 * if the driver is busy and cannot service the read request immediately.
948 * If EAGAIN is returned the caller should wait a little and retry the
949 * read.
950 *
951 * The format of the string returned in buf is:
952 * "offset:<offset> length:<lenvalue> data:<datavalues>
953 * where: <offset> is the last scratch pad register offset
954 * written to this file
955 * <lenvalue> is the last scratch pad register transfer length
956 * written to this file
957 * <datavalue> space separated list of <lenvalue> scratch pad
958 * register values in OxXX format
959 */
960ssize_t show_scratch_pad(struct device *dev, struct device_attribute *attr,
961 char *buf)
962{
963 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
964 u8 data[MAX_SCRATCH_PAD_TRANSFER_SIZE];
965 u8 idx;
966 enum scratch_pad_status scratch_pad_status;
967 int status = -EINVAL;
968
969
970 MHL_TX_DBG_INFO(dev_context, "called\n");
971
972 if (down_interruptible(&dev_context->isr_lock))
973 return -ERESTARTSYS;
974
975 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
976 status = -ENODEV;
977 goto err_exit;
978 }
979
980 if (dev_context->mhl_flags & MHL_STATE_FLAG_CONNECTED) {
981
982 scratch_pad_status = si_get_scratch_pad_vector(dev_context,
983 dev_context->spad_offset,
984 dev_context->spad_xfer_length,
985 data);
986
987 switch (scratch_pad_status) {
988 case SCRATCHPAD_SUCCESS:
989 status = scnprintf(buf, PAGE_SIZE, "offset:0x%02x " \
990 "length:0x%02x data:",
991 dev_context->spad_offset,
992 dev_context->spad_xfer_length);
993
994 for (idx = 0; idx < dev_context->spad_xfer_length; idx++) {
995 status += scnprintf(&buf[status], PAGE_SIZE, "0x%02x ", data[idx]);
996 }
997 break;
998
999 case SCRATCHPAD_BUSY:
1000 status = -EAGAIN;
1001 break;
1002
1003 default:
1004 status = -EFAULT;
1005 break;
1006 }
1007 }
1008
1009err_exit:
1010 up(&dev_context->isr_lock);
1011
1012 return status;
1013}
1014
1015/*
1016 * send_debug() - Handle write request to the debug attribute file.
1017 *
1018 * This file is used to either perform a write to registers of the transmitter
1019 * or to set the address, offset and byte count for a subsequent from the
1020 * register(s) of the transmitter.
1021 *
1022 * The format of the string in buf must be:
1023 * address=<pageaddr> offset=<offset_value> length=<Length_value> \
1024 * data=data_byte_0 ... data_byte_length-1
1025 * where: <pageaddr> specifies the I2C register page of the register(s)
1026 * to be written/read
1027 * <offset_value> specifies the starting register offset within the
1028 * register page to begin writing/reading
1029 * <length_value> number registers to be written/read
1030 * data_byte space separated list of <length_value> data bytes
1031 * to be written. If no data bytes are present then
1032 * the write to this file will only be used to set
1033 * the page address, offset and length for a
1034 * subsequent read from this file.
1035 */
1036ssize_t send_debug(struct device *dev, struct device_attribute *attr,
1037 const char *buf, size_t count)
1038{
1039 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
1040 unsigned long address = 0x100; /* initialize with invalid values */
1041 unsigned long offset = 0x100;
1042 unsigned long length = 0x100;
1043 unsigned long value;
1044 u8 data[MAX_DEBUG_TRANSFER_SIZE];
1045 u8 idx;
1046 char *str;
1047 char *endptr;
1048 int status = -EINVAL;
1049
1050 MHL_TX_DBG_INFO(dev_context, "received string: ""%s""\n", buf);
1051
1052 /*
1053 * Parse the input string and extract the scratch pad register selection
1054 * parameters
1055 */
1056 str = strstr(buf, "address=");
1057 if (str != NULL) {
1058 address = simple_strtoul(str + 8, NULL, 0);
1059 if (address > 0xFF) {
1060 MHL_TX_DBG_ERR(dev_context, "Invalid page address: 0x%02lx specified\n", address);
1061 goto err_exit_2;
1062 }
1063 } else {
1064 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""address"" parameter\n");
1065 goto err_exit_2;
1066 }
1067
1068 str = strstr(buf, "offset=");
1069 if (str != NULL) {
1070 offset = simple_strtoul(str + 7, NULL, 0);
1071 if (offset > 0xFF) {
1072 MHL_TX_DBG_ERR(dev_context, "Invalid page offset: 0x%02lx specified\n", offset);
1073 goto err_exit_2;
1074 }
1075 } else {
1076 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""offset"" value\n");
1077 goto err_exit_2;
1078 }
1079
1080 str = strstr(buf, "length=");
1081 if (str != NULL) {
1082 length = simple_strtoul(str + 7, NULL, 0);
1083 if (length > MAX_DEBUG_TRANSFER_SIZE) {
1084 MHL_TX_DBG_ERR(dev_context, "Transfer size 0x%02lx is too large\n", length);
1085 goto err_exit_2;
1086 }
1087 } else {
1088 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find ""length"" value\n");
1089 goto err_exit_2;
1090 }
1091
1092 str = strstr(buf, "data=");
1093 if (str != NULL) {
1094
1095 str += 5;
1096 endptr = str;
1097 for(idx = 0; idx < length; idx++) {
1098 endptr += strspn(endptr, white_space);
1099 str = endptr;
1100 if (*str == 0) {
1101 MHL_TX_DBG_ERR(dev_context, "Too few data values provided\n");
1102 goto err_exit_2;
1103 }
1104
1105 value = simple_strtoul(str, &endptr, 0);
1106
1107 if (value > 0xFF) {
1108 MHL_TX_DBG_ERR(dev_context, "Invalid register data value detected\n");
1109 goto err_exit_2;
1110 }
1111
1112 data[idx] = value;
1113 }
1114
1115
1116 } else {
1117 idx = 0;
1118 }
1119
1120 if ((offset + length) > 0x100) {
1121 MHL_TX_DBG_ERR(dev_context
1122 , "Invalid offset/length combination entered 0x%02x/0x%02x"
1123 , offset, length);
1124 goto err_exit_2;
1125 }
1126
1127 dev_context->debug_i2c_address = address;
1128 dev_context->debug_i2c_offset = offset;
1129 dev_context->debug_i2c_xfer_length = length;
1130
1131 if (idx == 0) {
1132 MHL_TX_DBG_INFO(dev_context, "No data specified, storing address "\
1133 "offset and length for subsequent debug read\n");
1134 goto err_exit_2;
1135 }
1136
1137 if (down_interruptible(&dev_context->isr_lock))
1138 return -ERESTARTSYS;
1139
1140 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
1141 status = -ENODEV;
1142 goto err_exit_1;
1143 }
1144
1145 status = dev_context->drv_info->mhl_device_dbg_i2c_reg_xfer(
1146 &dev_context->drv_context,
1147 address, offset, length,
1148 DEBUG_I2C_WRITE, data);
1149 if (status == 0)
1150 status = count;
1151
1152err_exit_1:
1153 up(&dev_context->isr_lock);
1154
1155err_exit_2:
1156 return status;
1157}
1158
1159/*
1160 * show_debug() - Handle read request to the debug attribute file.
1161 *
1162 * Reads from this file return one or more transmitter register values in
1163 * hexadecimal string format. The registers returned are specified by the
1164 * address, offset and length values previously written to this file.
1165 *
1166 * The return value is the number characters written to buf, or an error
1167 * code if the I2C read fails.
1168 *
1169 * The format of the string returned in buf is:
1170 * "address:<pageaddr> offset:<offset> length:<lenvalue> data:<datavalues>
1171 * where: <pageaddr> is the last I2C register page address written
1172 * to this file
1173 * <offset> is the last register offset written to this file
1174 * <lenvalue> is the last register transfer length written
1175 * to this file
1176 * <datavalue> space separated list of <lenvalue> register
1177 * values in OxXX format
1178 */
1179ssize_t show_debug(struct device *dev, struct device_attribute *attr, char *buf)
1180{
1181 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
1182 u8 data[MAX_DEBUG_TRANSFER_SIZE];
1183 u8 idx;
1184 int status = -EINVAL;
1185
1186 MHL_TX_DBG_INFO(dev_context, "called\n");
1187
1188 if (down_interruptible(&dev_context->isr_lock))
1189 return -ERESTARTSYS;
1190
1191 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
1192 status = -ENODEV;
1193 goto no_dev;
1194 }
1195
1196 status = dev_context->drv_info->mhl_device_dbg_i2c_reg_xfer(
1197 &dev_context->drv_context,
1198 dev_context->debug_i2c_address,
1199 dev_context->debug_i2c_offset,
1200 dev_context->debug_i2c_xfer_length,
1201 DEBUG_I2C_READ, data);
1202no_dev:
1203 up(&dev_context->isr_lock);
1204
1205 if (status == 0) {
1206
1207 status = scnprintf(buf, PAGE_SIZE, "address:0x%02x offset:0x%02x " \
1208 "length:0x%02x data:",
1209 dev_context->debug_i2c_address,
1210 dev_context->debug_i2c_offset,
1211 dev_context->debug_i2c_xfer_length);
1212
1213 for (idx = 0; idx < dev_context->debug_i2c_xfer_length; idx++) {
1214 status += scnprintf(&buf[status], PAGE_SIZE, "0x%02x ", data[idx]);
1215 }
1216 }
1217
1218 return status;
1219}
1220
1221
1222//( begin trace_level API
1223/*
1224 * show_trace_level() - Handle read request to the trace_level attribute file.
1225 *
1226 * The return value is the number characters written to buf, or EAGAIN
1227 * if the driver is busy and cannot service the read request immediately.
1228 * If EAGAIN is returned the caller should wait a little and retry the
1229 * read.
1230 */
1231ssize_t get_trace_level(struct device *dev, struct device_attribute *attr, char *buf)
1232{
1233 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
1234 int status = -EINVAL;
1235 extern int debug_msgs;
1236
1237
1238 if (down_interruptible(&dev_context->isr_lock)){
1239 MHL_TX_DBG_ERR(dev_context,"-ERESTARTSYS\n");
1240 return -ERESTARTSYS;
1241 }
1242
1243 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
1244 MHL_TX_DBG_ERR(dev_context,"-ENODEV\n");
1245 status = -ENODEV;
1246 goto err_exit;
1247 }
1248
1249 status = scnprintf(buf, PAGE_SIZE, "level=%d",debug_msgs );
1250 MHL_TX_DBG_INFO(dev_context,"buf:%c%s%c\n",'"',buf,'"');
1251
1252err_exit:
1253 up(&dev_context->isr_lock);
1254
1255 return status;
1256}
1257
1258/*
1259 * set_trace_level() - Handle write request to the trace_level attribute file.
1260 *
1261 * Writes to this file cause a RAP message with the specified action code
1262 * to be sent to the downstream device.
1263 */
1264ssize_t set_trace_level(struct device *dev, struct device_attribute *attr,
1265 const char *buf, size_t count)
1266{
1267 struct mhl_dev_context *dev_context = dev_get_drvdata(dev);
1268 int status;
1269 char *str;
1270 const char *key="level=";
1271 extern int debug_msgs;
1272
1273 /* Assume success */
1274 status = count;
1275
1276 MHL_TX_DBG_INFO(dev_context, "received string: %s\n", buf);
1277
1278 if (down_interruptible(&dev_context->isr_lock))
1279 return -ERESTARTSYS;
1280
1281 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN) {
1282 status = -ENODEV;
1283 goto err_exit;
1284 }
1285 str = strstr(buf, key);
1286 if (str != NULL) {
1287 debug_msgs = simple_strtol(str + strlen(key), NULL, 0);
1288 } else {
1289 MHL_TX_DBG_ERR(dev_context, "Invalid string format, can't find \"%s\" parameter\n",key);
1290 }
1291
1292err_exit:
1293 up(&dev_context->isr_lock);
1294
1295 return status;
1296}
1297
1298//) end trace_level API
1299
1300#define MAX_EVENT_STRING_LEN 128
1301/*
1302 * Handler for event notifications from the MhlTx layer.
1303 *
1304 */
1305 #define MTK_MHL_NOTIFY_SYS
1306
1307void mhl_event_notify(struct mhl_dev_context *dev_context, u32 event, u32 event_param, void *data)
1308{
1309 char event_string[MAX_EVENT_STRING_LEN];
1310 char *envp[] = {event_string, NULL};
1311 char *buf;
1312 u32 length;
1313 u32 count;
1314 int idx;
1315
1316 MHL_TX_DBG_INFO(dev_context, "called, event: 0x%08x "\
1317 "event_param: 0x%08x\n", event, event_param);
1318
1319 /*
1320 * Save the info on the most recent event. This is done to support the
1321 * SII_MHL_GET_MHL_TX_EVENT IOCTL. If at some point in the future the
1322 * driver's IOCTL interface is abandoned in favor of using sysfs attributes
1323 * this can be removed.
1324 */
1325 dev_context->pending_event = event;
1326 dev_context->pending_event_data = event_param;
1327
1328 switch(event) {
1329
1330 case MHL_TX_EVENT_SMB_DATA:
1331 case MHL_TX_EVENT_HPD_CLEAR:
1332 case MHL_TX_EVENT_HPD_GOT:
1333 case MHL_TX_EVENT_DEV_CAP_UPDATE:
1334 case MHL_TX_EVENT_EDID_UPDATE:
1335 case MHL_TX_EVENT_EDID_DONE:
1336 Notify_AP_MHL_TX_Event(event, event_param, data);
1337 break;
1338
1339 case MHL_TX_EVENT_CONNECTION:
1340 dev_context->mhl_flags |= MHL_STATE_FLAG_CONNECTED;
1341
1342#ifdef MEDIA_DATA_TUNNEL_SUPPORT
1343// mdt_init(dev_context);
1344#endif
1345#ifdef RCP_INPUTDEV_SUPPORT
1346 //init_rcp_input_dev(dev_context);
1347#endif
1348
1349#ifndef MTK_MHL_NOTIFY_SYS
1350 sysfs_notify(&dev_context->mhl_dev->kobj, NULL,
1351 __stringify(SYS_ATTR_NAME_CONN));
1352
1353 strncpy(event_string, "MHLEVENT=connected", MAX_EVENT_STRING_LEN);
1354 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1355#else
1356
1357#endif
1358 Notify_AP_MHL_TX_Event(event, event_param, data);
1359 break;
1360
1361 case MHL_TX_EVENT_DISCONNECTION:
1362 dev_context->mhl_flags = 0;
1363 dev_context->rcp_key_code = 0;
1364 dev_context->rcp_err_code = 0;
1365 dev_context->rcp_send_status = 0;
1366 dev_context->ucp_key_code = 0;
1367 dev_context->ucp_err_code = 0;
1368 dev_context->spad_send_status = 0;
1369 dev_context->misc_flags.flags.have_complete_devcap = false;//SET the para to default;
1370
1371#ifdef MEDIA_DATA_TUNNEL_SUPPORT
1372// mdt_destroy(dev_context);
1373#endif
1374#ifdef RCP_INPUTDEV_SUPPORT
1375 //destroy_rcp_input_dev(dev_context);
1376#endif
1377
1378#ifndef MTK_MHL_NOTIFY_SYS
1379 sysfs_notify(&dev_context->mhl_dev->kobj, NULL,
1380 __stringify(SYS_ATTR_NAME_CONN));
1381
1382 strncpy(event_string, "MHLEVENT=disconnected", MAX_EVENT_STRING_LEN);
1383 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1384#else
1385
1386#endif
1387
1388 Notify_AP_MHL_TX_Event(event, event_param, data);
1389 break;
1390
1391 case MHL_TX_EVENT_RCP_RECEIVED:
1392
1393#ifdef RCP_INPUTDEV_SUPPORT
1394 if (0 == generate_rcp_input_event(dev_context, (uint8_t)event_param))
1395 si_mhl_tx_rcpk_send(dev_context, (uint8_t)event_param);
1396 else
1397 {
1398 si_mhl_tx_rcpe_send(dev_context, MHL_RCPE_STATUS_INEEFECTIVE_KEY_CODE);
1399 si_mhl_tx_rcpk_send(dev_context, (uint8_t)event_param);
1400 }
1401#else
1402 dev_context->mhl_flags &= ~MHL_STATE_FLAG_RCP_SENT;
1403 dev_context->mhl_flags |= MHL_STATE_FLAG_RCP_RECEIVED;
1404 dev_context->rcp_key_code = event_param;
1405
1406#ifndef MTK_MHL_NOTIFY_SYS
1407 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_RCP));
1408
1409 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_RCP key code=0x%02x", event_param);
1410 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1411#else
1412
1413#endif
1414 break;
1415
1416 case MHL_TX_EVENT_RCPK_RECEIVED:
1417 if ((dev_context->mhl_flags & MHL_STATE_FLAG_RCP_SENT)
1418 && (dev_context->rcp_key_code == event_param)) {
1419
1420 dev_context->rcp_err_code = 0;
1421 dev_context->mhl_flags |= MHL_STATE_FLAG_RCP_ACK;
1422
1423 MHL_TX_DBG_INFO(dev_context, "Generating RCPK received event, keycode: 0x%02x\n", event_param);
1424
1425#ifndef MTK_MHL_NOTIFY_SYS
1426
1427 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_RCPK));
1428
1429 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_RCPK key code=0x%02x", event_param);
1430 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1431#else
1432
1433#endif
1434 } else {
1435 MHL_TX_DBG_ERR(dev_context, "Ignoring unexpected RCPK received event, keycode: 0x%02x\n", event_param);
1436 }
1437 break;
1438
1439 case MHL_TX_EVENT_RCPE_RECEIVED:
1440 if (dev_context->mhl_flags & MHL_STATE_FLAG_RCP_SENT) {
1441
1442 dev_context->rcp_err_code = event_param;
1443 dev_context->mhl_flags |= MHL_STATE_FLAG_RCP_NAK;
1444
1445 MHL_TX_DBG_INFO(dev_context, "Generating RCPE received event, error code: 0x%02x\n", event_param);
1446#ifndef MTK_MHL_NOTIFY_SYS
1447 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_RCPK));
1448
1449 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_RCPE error code=0x%02x", event_param);
1450 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1451#else
1452
1453#endif
1454 } else {
1455 MHL_TX_DBG_ERR(dev_context, "Ignoring unexpected RCPE received event, error code: 0x%02x\n", event_param);
1456 }
1457 break;
1458#endif /* #ifdef RCP_INPUTDEV_SUPPORT */
1459
1460 case MHL_TX_EVENT_UCP_RECEIVED:
1461 dev_context->mhl_flags &= ~MHL_STATE_FLAG_UCP_SENT;
1462 dev_context->mhl_flags |= MHL_STATE_FLAG_UCP_RECEIVED;
1463 dev_context->ucp_key_code = event_param;
1464#ifndef MTK_MHL_NOTIFY_SYS
1465 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_UCP));
1466
1467 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_UCP key code=0x%02x", event_param);
1468 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1469#else
1470
1471#endif
1472 break;
1473
1474 case MHL_TX_EVENT_UCPK_RECEIVED:
1475 if ((dev_context->mhl_flags & MHL_STATE_FLAG_UCP_SENT)
1476 && (dev_context->ucp_key_code == event_param)) {
1477
1478 dev_context->mhl_flags |= MHL_STATE_FLAG_UCP_ACK;
1479
1480 MHL_TX_DBG_INFO(dev_context, "Generating UCPK received event, keycode: 0x%02x\n", event_param);
1481#ifndef MTK_MHL_NOTIFY_SYS
1482 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_UCPK));
1483
1484 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_UCPK key code=0x%02x", event_param);
1485 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1486#else
1487
1488#endif
1489 } else {
1490 MHL_TX_DBG_ERR(dev_context, "Ignoring unexpected UCPK received event, keycode: 0x%02x\n", event_param);
1491 }
1492 break;
1493
1494 case MHL_TX_EVENT_UCPE_RECEIVED:
1495 if (dev_context->mhl_flags & MHL_STATE_FLAG_UCP_SENT) {
1496
1497 dev_context->ucp_err_code = event_param;
1498 dev_context->mhl_flags |= MHL_STATE_FLAG_UCP_NAK;
1499
1500 MHL_TX_DBG_INFO(dev_context, "Generating UCPE received event, error code: 0x%02x\n", event_param);
1501#ifndef MTK_MHL_NOTIFY_SYS
1502 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_UCPK));
1503
1504 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_UCPE error code=0x%02x", event_param);
1505 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1506#else
1507
1508#endif
1509 } else {
1510 MHL_TX_DBG_ERR(dev_context, "Ignoring unexpected UCPE received event, error code: 0x%02x\n", event_param);
1511 }
1512 break;
1513
1514 case MHL_TX_EVENT_SPAD_RECEIVED:
1515 length = event_param;
1516 buf = data;
1517
1518#ifndef MTK_MHL_NOTIFY_SYS
1519 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_SPAD));
1520
1521 idx = snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=SPAD_CHG length=0x%02x data=", length);
1522
1523 count = 0;
1524 while (idx < MAX_EVENT_STRING_LEN) {
1525 if (count >= length)
1526 break;
1527
1528 idx += snprintf(&event_string[idx], MAX_EVENT_STRING_LEN - idx, "0x%02x ", buf[count]);
1529 count++;
1530 }
1531
1532 if (idx < MAX_EVENT_STRING_LEN) {
1533 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1534 } else {
1535 MHL_TX_DBG_ERR(dev_context, "Buffer too small to contain scratch pad data!\n");
1536 }
1537#else
1538
1539#endif
1540 break;
1541
1542 case MHL_TX_EVENT_POW_BIT_CHG:
1543 MHL_TX_DBG_INFO(dev_context, "Generating VBUS power bit change event, POW bit is %s\n", event_param? "ON" : "OFF");
1544#ifndef MTK_MHL_NOTIFY_SYS
1545 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=MHL VBUS power %s", event_param? "ON" : "OFF");
1546 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1547#else
1548
1549#endif
1550 break;
1551
1552 case MHL_TX_EVENT_RAP_RECEIVED:
1553 MHL_TX_DBG_INFO(dev_context, "Generating RAP received event, action code: 0x%02x\n", event_param);
1554#ifndef MTK_MHL_NOTIFY_SYS
1555
1556 sysfs_notify(&dev_context->mhl_dev->kobj, NULL, __stringify(SYS_ATTR_NAME_RAP));
1557
1558 snprintf(event_string, MAX_EVENT_STRING_LEN, "MHLEVENT=received_RAP action code=0x%02x", event_param);
1559 kobject_uevent_env(&dev_context->mhl_dev->kobj, KOBJ_CHANGE, envp);
1560#else
1561
1562#endif
1563 break;
1564
1565 default:
1566 MHL_TX_DBG_ERR(dev_context, "called with unrecognized event code!\n");
1567 }
1568}
1569
1570/*
1571 * File operations supported by the MHL driver
1572 */
1573static const struct file_operations mhl_fops = {
1574 .owner = THIS_MODULE
1575};
1576
1577/*
1578 * Sysfs attribute files supported by this driver.
1579 */
1580struct device_attribute driver_attribs[] = {
1581 __ATTR(SYS_ATTR_NAME_CONN ,0444,show_connection_state, NULL),
1582#ifndef RCP_INPUTDEV_SUPPORT
1583 __ATTR(SYS_ATTR_NAME_RCP ,0444,show_rcp , send_rcp),
1584 __ATTR(SYS_ATTR_NAME_RCPK ,0444,show_rcp_ack , send_rcp_ack),
1585#endif
1586 __ATTR(SYS_ATTR_NAME_RAP ,0444,show_rap , send_rap),
1587 __ATTR(SYS_ATTR_NAME_RAP_STATUS ,0444,show_rap_status , set_rap_status),
1588 __ATTR(SYS_ATTR_NAME_DEVCAP ,0444,show_dev_cap , select_dev_cap),
1589 __ATTR(SYS_ATTR_NAME_UCP ,0444,show_ucp , send_ucp),
1590 __ATTR(SYS_ATTR_NAME_UCPK ,0444,show_ucp_ack , send_ucp_ack),
1591 __ATTR(SYS_ATTR_NAME_SPAD ,0444,show_scratch_pad , send_scratch_pad),
1592 __ATTR(SYS_ATTR_NAME_DEBUG ,0444,show_debug , send_debug),
1593 __ATTR(SYS_ATTR_NAME_TRACE_LEVEL ,0444,get_trace_level , set_trace_level),
1594 __ATTR_NULL
1595};
1596
1597static void mhl8338_irq_handler(void)
1598{
1599 atomic_set(&mhl_irq_event, 1);
1600 wake_up_interruptible(&mhl_irq_wq);
1601 //mt65xx_eint_unmask(CUST_EINT_HDMI_HPD_NUM);
1602}
1603
1604static void mhl_irq_handler(int irq, void *data);
1605
1606static int irq_cnt = 0;
1607static int mhl_irq_kthread(void *data)
1608{
1609 int i=0;
1610 struct sched_param param = { .sched_priority = RTPM_PRIO_SCRN_UPDATE };
1611 sched_setscheduler(current, SCHED_RR, &param);
1612
1613 for( ;; ) {
1614 set_current_state(TASK_INTERRUPTIBLE);
1615 wait_event_interruptible(mhl_irq_wq, atomic_read(&mhl_irq_event));
1616 set_current_state(TASK_RUNNING);
1617 irq_cnt++;
1618 //hdmi_update_impl();
1619
1620 atomic_set(&mhl_irq_event, 0);
1621 //for( i=0;i<30; i++)
1622 mhl_irq_handler(0, si_dev_context);
1623
1624 if (kthread_should_stop())
1625 break;
1626#ifdef CUST_EINT_MHL_NUM
1627 mt_eint_unmask(CUST_EINT_MHL_NUM);
1628#endif
1629 }
1630
1631 return 0;
1632}
1633
1634/*
1635 * Interrupt handler for MHL transmitter interrupts.
1636 *
1637 * @irq: The number of the asserted IRQ line that caused
1638 * this handler to be called.
1639 * @data: Data pointer passed when the interrupt was enabled,
1640 * which in this case is a pointer to an mhl_dev_context struct.
1641 *
1642 * Always returns IRQ_HANDLED.
1643 */
1644static void mhl_irq_handler(int irq, void *data)
1645{
1646 struct mhl_dev_context *dev_context = (struct mhl_dev_context *)data;
1647
1648
1649 if (!down_interruptible(&dev_context->isr_lock)) {
1650 if (dev_context->dev_flags & DEV_FLAG_SHUTDOWN)
1651 goto irq_done;
1652 if (dev_context->dev_flags & DEV_FLAG_COMM_MODE)
1653 goto irq_done;
1654
1655 memset(&dev_context->intr_info, 0, sizeof(*(&dev_context->intr_info)));
1656
1657 dev_context->intr_info.edid_parser_context = dev_context->edid_parser_context;
1658
1659 dev_context->drv_info->mhl_device_isr((struct drv_hw_context *)
1660 (&dev_context->drv_context),
1661 &dev_context->intr_info);
1662
1663 /* Now post process events detected by the interrupt handler */
1664 if(dev_context->intr_info.flags & DRV_INTR_FLAG_DISCONNECT) {
1665 dev_context->misc_flags.flags.rap_content_on = false;
1666 dev_context->misc_flags.flags.mhl_rsen = false;
1667 dev_context->mhl_connection_event = true;
1668 dev_context->mhl_connected = MHL_TX_EVENT_DISCONNECTION;
1669 si_mhl_tx_process_events(dev_context);
1670 } else {
1671 if (dev_context->intr_info.flags & DRV_INTR_FLAG_CONNECT) {
1672 dev_context->misc_flags.flags.rap_content_on = true;
1673 dev_context->rap_sub_command = MHL_RAP_CONTENT_ON;
1674 dev_context->misc_flags.flags.mhl_rsen = true;
1675 dev_context->mhl_connection_event = true;
1676 dev_context->mhl_connected = MHL_TX_EVENT_CONNECTION;
1677 si_mhl_tx_process_events(dev_context);
1678 }
1679
1680 if (dev_context->intr_info.flags & DRV_INTR_FLAG_CBUS_ABORT)
1681 process_cbus_abort(dev_context);
1682
1683 if (dev_context->intr_info.flags & DRV_INTR_FLAG_WRITE_BURST)
1684 si_mhl_tx_process_write_burst_data(dev_context);
1685
1686 if (dev_context->intr_info.flags & DRV_INTR_FLAG_SET_INT)
1687 si_mhl_tx_got_mhl_intr(dev_context,
1688 dev_context->intr_info.int_msg[0],
1689 dev_context->intr_info.int_msg[1]);
1690
1691 if (dev_context->intr_info.flags & DRV_INTR_FLAG_MSC_DONE)
1692 si_mhl_tx_msc_command_done(dev_context,
1693 dev_context->intr_info.msc_done_data);
1694
1695 if (dev_context->intr_info.flags & DRV_INTR_FLAG_HPD_CHANGE)
1696 si_mhl_tx_notify_downstream_hpd_change(dev_context,
1697 dev_context->intr_info.hpd_status);
1698
1699 if (dev_context->intr_info.flags & DRV_INTR_FLAG_WRITE_STAT)
1700 si_mhl_tx_got_mhl_status(dev_context,
1701 dev_context->intr_info.write_stat[0],
1702 dev_context->intr_info.write_stat[1]);
1703
1704 if (dev_context->intr_info.flags & DRV_INTR_FLAG_MSC_RECVD) {
1705 dev_context->msc_msg_arrived = true;
1706 dev_context->msc_msg_sub_command = dev_context->intr_info.msc_msg[0];
1707 dev_context->msc_msg_data = dev_context->intr_info.msc_msg[1];
1708 si_mhl_tx_process_events(dev_context);
1709 }
1710 }
1711
1712 /*
1713 * Check to see if we can send any messages that may have
1714 * been queued up as the result of interrupt processing.
1715 */
1716 si_mhl_tx_drive_states(dev_context);
1717
1718// if(sii_mhl_connected != dev_context->mhl_connected)
1719// pr_err("MHL connected status %d -> %d\n",sii_mhl_connected, dev_context->mhl_connected);
1720irq_done:
1721 up(&dev_context->isr_lock);
1722 }
1723
1724}
1725
1726/* APIs provided by the MHL layer to the lower level driver */
1727
1728int mhl_tx_init(struct mhl_drv_info const *drv_info, struct i2c_client *client)
1729{
1730 ///struct mhl_dev_context *dev_context;
1731 int ret,dummy;
1732
1733
1734 if (drv_info == NULL || client == NULL) {
1735 pr_err("Null parameter passed to %s\n",__FUNCTION__);
1736 return -EINVAL;
1737 }
1738
1739 init_waitqueue_head(&mhl_irq_wq);
1740 mhl_irq_task = kthread_create(mhl_irq_kthread, NULL, "mhl_irq_kthread");
1741 wake_up_process(mhl_irq_task);
1742
1743 #ifdef CONFIG_MTK_SMARTBOOK_SUPPORT
1744 init_waitqueue_head(&smartbook_wq);
1745 smartbook_task = kthread_create(smartbook_kthread, NULL, "smartbook_kthread");
1746 wake_up_process(smartbook_task);
1747 #endif
1748
1749 si_dev_context = kzalloc(sizeof(*si_dev_context) + drv_info->drv_context_size, GFP_KERNEL);
1750 if (!si_dev_context) {
1751 dev_err(&client->dev, "failed to allocate driver data\n");
1752 return -ENOMEM;
1753 }
1754
1755 si_dev_context->signature = MHL_DEV_CONTEXT_SIGNATURE;
1756 si_dev_context->drv_info = drv_info;
1757 si_dev_context->client = client;
1758
1759 sema_init(&si_dev_context->isr_lock, 1);
1760 INIT_LIST_HEAD(&si_dev_context->timer_list);
1761 si_dev_context->timer_work_queue = create_workqueue(MHL_DRIVER_NAME);
1762 if (si_dev_context->timer_work_queue == NULL) {
1763 ret = -ENOMEM;
1764 goto free_mem;
1765 }
1766
1767 if (mhl_class == NULL) {
1768 mhl_class = class_create(THIS_MODULE, "mhl");
1769 if(IS_ERR(mhl_class)) {
1770 ret = PTR_ERR(mhl_class);
1771 pr_info("class_create failed %d\n", ret);
1772 goto err_exit;
1773 }
1774
1775 mhl_class->dev_attrs = driver_attribs;
1776
1777 ret = alloc_chrdev_region(&dev_num,
1778 0, MHL_DRIVER_MINOR_MAX,
1779 MHL_DRIVER_NAME);
1780
1781 if (ret) {
1782 pr_info("register_chrdev %s failed, error code: %d\n", MHL_DRIVER_NAME, ret);
1783 goto free_class;
1784 }
1785
1786 cdev_init(&si_dev_context->mhl_cdev, &mhl_fops);
1787 si_dev_context->mhl_cdev.owner = THIS_MODULE;
1788 ret = cdev_add(&si_dev_context->mhl_cdev, MINOR(dev_num), MHL_DRIVER_MINOR_MAX);
1789 if (ret) {
1790 pr_info("cdev_add %s failed %d\n", MHL_DRIVER_NAME, ret);
1791 goto free_chrdev;
1792 }
1793 }
1794
1795 si_dev_context->mhl_dev = device_create(mhl_class, &si_dev_context->client->dev,
1796 dev_num, si_dev_context,
1797 "%s", MHL_DEVICE_NAME);
1798 if (IS_ERR(si_dev_context->mhl_dev)) {
1799 ret = PTR_ERR(si_dev_context->mhl_dev);
1800 pr_info("device_create failed %s %d\n", MHL_DEVICE_NAME, ret);
1801 goto free_cdev;
1802 }
1803
1804#ifdef CUST_EINT_MHL_NUM
1805 mt_eint_registration(CUST_EINT_MHL_NUM, CUST_EINT_MHL_TYPE, &mhl8338_irq_handler, 0);
1806 mt_eint_mask(CUST_EINT_MHL_NUM);
1807#else
1808 printk("%s,%d Error: CUST_EINT_MHL_NUM is not defined\n", __func__, __LINE__);
1809#endif
1810 /* Initialize the MHL transmitter hardware. */
1811 ret = down_interruptible(&si_dev_context->isr_lock);
1812 if (ret) {
1813 dev_err(&client->dev, "failed to acquire ISR semaphore, status: %d\n", ret);
1814 goto free_irq_handler;
1815 }
1816
1817 i2c_set_clientdata(client, si_dev_context);
1818
1819 /* initialize the PCA 950x GPIO expander, if present */
1820 //ret = gpio_expander_init(dev_context);
1821 //if (ret < 0) {
1822 // dev_err(&client->dev,"failed to initialize GPIO expander, status: %d\n",ret);
1823 // goto free_irq_handler;
1824 //}
1825
1826 /* Initialize EDID parser module */
1827 si_dev_context->edid_parser_context = si_edid_create_context(si_dev_context,&si_dev_context->drv_context);
1828
1829 ret = si_mhl_tx_initialize(si_dev_context, true);
1830 up(&si_dev_context->isr_lock);
1831
1832#ifdef RCP_INPUTDEV_SUPPORT
1833 init_rcp_input_dev(si_dev_context);
1834#endif
1835
1836 MHL_TX_DBG_INFO(si_dev_context, "MHL transmitter successfully initialized\n");
1837
1838 return ret;
1839
1840free_irq_handler:
1841 i2c_set_clientdata(client, NULL);
1842 dummy = down_interruptible(&si_dev_context->isr_lock);
1843 if(si_dev_context->edid_parser_context)
1844 si_edid_destroy_context(si_dev_context->edid_parser_context);
1845
1846 free_irq(si_dev_context->client->irq, si_dev_context);
1847
1848free_device:
1849 device_destroy(mhl_class, dev_num);
1850
1851free_cdev:
1852 cdev_del(&si_dev_context->mhl_cdev);
1853
1854free_chrdev:
1855 unregister_chrdev_region(dev_num, MHL_DRIVER_MINOR_MAX);
1856 dev_num = 0;
1857
1858free_class:
1859 class_destroy(mhl_class);
1860
1861err_exit:
1862 destroy_workqueue(si_dev_context->timer_work_queue);
1863
1864free_mem:
1865 kfree(si_dev_context);
1866
1867 return ret;
1868}
1869
1870int mhl_tx_remove(struct i2c_client *client)
1871{
1872 struct mhl_dev_context *dev_context;
1873 int ret = 0;
1874
1875 dev_context = i2c_get_clientdata(client);
1876
1877 if (dev_context != NULL){
1878 MHL_TX_DBG_INFO(dev_context, "%x\n",dev_context);
1879 ret = down_interruptible(&dev_context->isr_lock);
1880
1881 dev_context->dev_flags |= DEV_FLAG_SHUTDOWN;
1882
1883 ret = si_mhl_tx_shutdown(dev_context);
1884
1885 mhl_tx_destroy_timer_support(dev_context);
1886
1887 up(&dev_context->isr_lock);
1888
1889 free_irq(dev_context->client->irq, dev_context);
1890
1891 device_destroy(mhl_class, dev_num);
1892
1893 cdev_del(&dev_context->mhl_cdev);
1894
1895 unregister_chrdev_region(dev_num, MHL_DRIVER_MINOR_MAX);
1896 dev_num = 0;
1897
1898 class_destroy(mhl_class);
1899 mhl_class = NULL;
1900
1901#ifdef MEDIA_DATA_TUNNEL_SUPPORT
1902// mdt_destroy(dev_context);
1903#endif
1904#ifdef RCP_INPUTDEV_SUPPORT
1905 destroy_rcp_input_dev(dev_context);
1906#endif
1907
1908 si_edid_destroy_context(dev_context->edid_parser_context);
1909
1910 //mhl_tx_delete_timer(dev_context, dev_context->cbus_abort_timer); //TB added to clean up timer object
1911
1912 kfree(dev_context);
1913
1914 MHL_TX_DBG_INFO(dev_context, "%x\n",dev_context);
1915 }
1916 return ret;
1917}
1918
1919static void mhl_tx_destroy_timer_support(struct mhl_dev_context *dev_context)
1920{
1921 struct timer_obj *mhl_timer;
1922
1923 /*
1924 * Make sure all outstanding timer objects are canceled and the
1925 * memory allocated for them is freed.
1926 */
1927 while(!list_empty(&dev_context->timer_list)) {
1928 mhl_timer = list_first_entry(&dev_context->timer_list, struct timer_obj, list_link);
1929 hrtimer_cancel(&mhl_timer->hr_timer);
1930 list_del(&mhl_timer->list_link);
1931 kfree(mhl_timer);
1932 }
1933
1934 destroy_workqueue(dev_context->timer_work_queue);
1935 dev_context->timer_work_queue = NULL;
1936}
1937
1938static void mhl_tx_timer_work_handler(struct work_struct *work)
1939{
1940 struct timer_obj *mhl_timer;
1941
1942 mhl_timer = container_of(work, struct timer_obj, work_item);
1943
1944 mhl_timer->flags |= TIMER_OBJ_FLAG_WORK_IP;
1945 if (!down_interruptible(&mhl_timer->dev_context->isr_lock)) {
1946
1947 mhl_timer->timer_callback_handler(mhl_timer->callback_param);
1948
1949 up(&mhl_timer->dev_context->isr_lock);
1950 }
1951 mhl_timer->flags &= ~TIMER_OBJ_FLAG_WORK_IP;
1952
1953 if(mhl_timer->flags & TIMER_OBJ_FLAG_DEL_REQ) {
1954 /*
1955 * Deletion of this timer was requested during the execution of
1956 * the callback handler so go ahead and delete it now.
1957 */
1958 kfree(mhl_timer);
1959 }
1960}
1961
1962static enum hrtimer_restart mhl_tx_timer_handler(struct hrtimer *timer)
1963{
1964 struct timer_obj *mhl_timer;
1965
1966 mhl_timer = container_of(timer, struct timer_obj, hr_timer);
1967
1968 queue_work(mhl_timer->dev_context->timer_work_queue, &mhl_timer->work_item);
1969
1970 return HRTIMER_NORESTART;
1971}
1972
1973static int is_timer_handle_valid(struct mhl_dev_context *dev_context, void *timer_handle)
1974{
1975 struct timer_obj *timer;
1976
1977 list_for_each_entry(timer, &dev_context->timer_list, list_link) {
1978 if (timer == timer_handle)
1979 break;
1980 }
1981
1982 if(timer != timer_handle) {
1983 MHL_TX_DBG_ERR(dev_context, "Invalid timer handle %p received\n", timer_handle);
1984 return -EINVAL;
1985 }
1986 return 0;
1987}
1988
1989int mhl_tx_create_timer(void *context,
1990 void (*callback_handler)(void *callback_param),
1991 void *callback_param,
1992 void **timer_handle)
1993{
1994 struct mhl_dev_context *dev_context;
1995 struct timer_obj *new_timer;
1996
1997 dev_context = get_mhl_device_context(context);
1998
1999 if (callback_handler == NULL)
2000 return -EINVAL;
2001
2002 if (dev_context->timer_work_queue == NULL)
2003 return -ENOMEM;
2004
2005 new_timer = kmalloc(sizeof(*new_timer), GFP_KERNEL);
2006 if (new_timer == NULL)
2007 return -ENOMEM;
2008
2009 new_timer->timer_callback_handler = callback_handler;
2010 new_timer->callback_param = callback_param;
2011 new_timer->flags = 0;
2012
2013 new_timer->dev_context = dev_context;
2014 INIT_WORK(&new_timer->work_item, mhl_tx_timer_work_handler);
2015
2016 list_add(&new_timer->list_link, &dev_context->timer_list);
2017
2018 hrtimer_init(&new_timer->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
2019 new_timer->hr_timer.function = mhl_tx_timer_handler;
2020 *timer_handle = new_timer;
2021 return 0;
2022}
2023
2024int mhl_tx_delete_timer(void *context, void *timer_handle)
2025{
2026 struct mhl_dev_context *dev_context;
2027 struct timer_obj *timer;
2028 int status;
2029
2030 dev_context = get_mhl_device_context(context);
2031
2032 status = is_timer_handle_valid(dev_context, timer_handle);
2033 if (status == 0) {
2034 timer = timer_handle;
2035
2036 list_del(&timer->list_link);
2037
2038 hrtimer_cancel(&timer->hr_timer);
2039
2040 if(timer->flags & TIMER_OBJ_FLAG_WORK_IP) {
2041 /*
2042 * Request to delete timer object came from within the timer's
2043 * callback handler. If we were to proceed with the timer deletion
2044 * we would deadlock at cancel_work_sync(). So instead just flag
2045 * that the user wants the timer deleted. Later when the timer
2046 * callback completes the timer's work handler will complete the
2047 * process of deleting this timer.
2048 */
2049 timer->flags |= TIMER_OBJ_FLAG_DEL_REQ;
2050 } else {
2051 cancel_work_sync(&timer->work_item);
2052
2053 kfree(timer);
2054 }
2055 }
2056
2057 return status;
2058}
2059
2060int mhl_tx_start_timer(void *context, void *timer_handle, uint32_t time_msec)
2061{
2062 struct mhl_dev_context *dev_context;
2063 struct timer_obj *timer;
2064 ktime_t timer_period;
2065 int status;
2066
2067 dev_context = get_mhl_device_context(context);
2068
2069 status = is_timer_handle_valid(dev_context, timer_handle);
2070 if (status == 0) {
2071 timer = timer_handle;
2072
2073 timer_period = ktime_set(0, MSEC_TO_NSEC(time_msec));
2074 hrtimer_start(&timer->hr_timer, timer_period, HRTIMER_MODE_REL);
2075 }
2076
2077 return status;
2078}
2079
2080int mhl_tx_stop_timer(void *context, void *timer_handle)
2081{
2082 struct mhl_dev_context *dev_context;
2083 struct timer_obj *timer;
2084 int status;
2085
2086 dev_context = get_mhl_device_context(context);
2087
2088 status = is_timer_handle_valid(dev_context, timer_handle);
2089 if (status == 0) {
2090 timer = timer_handle;
2091
2092 hrtimer_cancel(&timer->hr_timer);
2093 }
2094 return status;
2095}