summaryrefslogtreecommitdiff
blob: 67ae5497097d7f0f521d03cc90dc3445dc2dafbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
/*
* LIRC driver for Nuvoton w83667hg/w83677hg-i
*
* Copyright (C) 2009 Nuvoton PS Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/version.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/pnp.h>

/*//#include <asm/semaphore.h>*/
#include <linux/semaphore.h>

#include <linux/device.h>
#include <asm-generic/ioctl.h>

#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/io.h>



#include "lirc_wb677_common_extern.h"



/* CIR settings */

/* total length of CIR and CIR WAKE */
#define CIR_IOREG_LENGTH 0x0f

/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL
 * 0x7d0 = 2000 */
#define CIR_RX_LIMIT_COUNT 0x7d0

/* CIR Regs */
#define CIR_IRCON   0x00
#define CIR_IRSTS   0x01
#define CIR_IREN    0x02
#define CIR_RXFCONT 0x03
#define CIR_CP      0x04
#define CIR_CC      0x05
#define CIR_SLCH    0x06
#define CIR_SLCL    0x07
#define CIR_FIFOCON 0x08
#define CIR_IRFIFOSTS 0x09
#define CIR_SRXFIFO 0x0A
#define CIR_TXFCONT 0x0B
#define CIR_STXFIFO 0x0C
#define CIR_FCCH    0x0D
#define CIR_FCCL    0x0E
#define CIR_IRFSM   0x0F

/* CIR IRCON settings */
#define CIR_IRCON_RECV   0x80
#define CIR_IRCON_WIREN  0x40
#define CIR_IRCON_TXEN   0x20
#define CIR_IRCON_RXEN   0x10
#define CIR_IRCON_WRXINV 0x08
#define CIR_IRCON_RXINV  0x04

#define CIR_IRCON_SAMPLE_PERIOD_SEL_1   0x00
#define CIR_IRCON_SAMPLE_PERIOD_SEL_25  0x01
#define CIR_IRCON_SAMPLE_PERIOD_SEL_50  0x02
#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03

/* select sample period as 50us */
#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50

/* CIR IRSTS settings */
#define CIR_IRSTS_RDR  0x80
#define CIR_IRSTS_RTR  0x40
#define CIR_IRSTS_PE   0x20
#define CIR_IRSTS_RFO  0x10
#define CIR_IRSTS_TE   0x08
#define CIR_IRSTS_TTR  0x04
#define CIR_IRSTS_TFU  0x02
#define CIR_IRSTS_GH   0x01

/* CIR IREN settings */
#define CIR_IREN_RDR  0x80
#define CIR_IREN_RTR  0x40
#define CIR_IREN_PE   0x20
#define CIR_IREN_RFO  0x10
#define CIR_IREN_TE   0x08
#define CIR_IREN_TTR  0x04
#define CIR_IREN_TFU  0x02
#define CIR_IREN_GH   0x01

/* CIR FIFOCON settings */
#define CIR_FIFOCON_TXFIFOCLR  0x80

#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00
#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10
#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20
#define CIR_FIFOCON_TX_TRIGGER_LEV_8  0x30

/* select TX trigger level as 16 */
#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16

#define CIR_FIFOCON_RXFIFOCLR  0x08

#define CIR_FIFOCON_RX_TRIGGER_LEV_1  0x00
#define CIR_FIFOCON_RX_TRIGGER_LEV_8  0x01
#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02
#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03

/* select RX trigger level as 1 */
#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_1

/* CIR IRFIFOSTS settings */
#define CIR_IRFIFOSTS_IR_PENDING  0x80
#define CIR_IRFIFOSTS_RX_GS       0x40
#define CIR_IRFIFOSTS_RX_FTA      0x20
#define CIR_IRFIFOSTS_RX_EMPTY    0x10
#define CIR_IRFIFOSTS_RX_FULL     0x08
#define CIR_IRFIFOSTS_TX_FTA      0x04
#define CIR_IRFIFOSTS_TX_EMPTY    0x02
#define CIR_IRFIFOSTS_TX_FULL     0x01


/* CIR WAKE UP Regs */
#define CIR_WAKE_IRCON   0x00
#define CIR_WAKE_IRSTS   0x01
#define CIR_WAKE_IREN    0x02
#define CIR_WAKE_FIFO_CMP_DEEP 0x03
#define CIR_WAKE_FIFO_CMP_TOL  0x04
#define CIR_WAKE_FIFO_COUNT    0x05
#define CIR_WAKE_SLCH    0x06
#define CIR_WAKE_SLCL    0x07
#define CIR_WAKE_FIFOCON 0x08
#define CIR_WAKE_SRXFSTS 0x09
#define CIR_WAKE_SAMPLE_RX_FIFO 0x0A
#define CIR_WAKE_WR_FIFO_DATA   0x0B
#define CIR_WAKE_RD_FIFO_ONLY   0x0C
#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0D
#define CIR_WAKE_FIFO_IGNORE 0x0E
#define CIR_WAKE_IRFSM   0x0F

/* CIR WAKE UP IRCON settings */
#define CIR_WAKE_IRCON_DEC_RST 0x80
#define CIR_WAKE_IRCON_MODE1   0x40
#define CIR_WAKE_IRCON_MODE0   0x20
#define CIR_WAKE_IRCON_RXEN    0x10
#define CIR_WAKE_IRCON_R       0x08
#define CIR_WAKE_IRCON_RXINV   0x04

/* select a same sample period like cir register */
#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50

/* CIR WAKE UP IRSTS settings */
#define CIR_WAKE_IRSTS_RDR        0x80
#define CIR_WAKE_IRSTS_RTR        0x40
#define CIR_WAKE_IRSTS_PE         0x20
#define CIR_WAKE_IRSTS_RFO        0x10
#define CIR_WAKE_IRSTS_GH         0x08
#define CIR_WAKE_IRSTS_IR_PENDING 0x01

/* CIR WAKE UP IREN settings */
#define CIR_WAKE_IREN_RDR  0x80
#define CIR_WAKE_IREN_RTR  0x40
#define CIR_WAKE_IREN_PE   0x20
#define CIR_WAKE_IREN_RFO  0x10
#define CIR_WAKE_IREN_TE   0x08
#define CIR_WAKE_IREN_TTR  0x04
#define CIR_WAKE_IREN_TFU  0x02
#define CIR_WAKE_IREN_GH   0x01

/* CIR WAKE FIFOCON settings */
#define CIR_WAKE_FIFOCON_RXFIFOCLR  0x08

#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03

/* select WAKE UP RX trigger level as 67 */
#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67

/* CIR WAKE SRXFSTS settings */
#define CIR_WAKE_IRFIFOSTS_RX_GS       0x80
#define CIR_WAKE_IRFIFOSTS_RX_FTA      0x40
#define CIR_WAKE_IRFIFOSTS_RX_EMPTY    0x20
#define CIR_WAKE_IRFIFOSTS_RX_FULL     0x10




/* Config Regs */

/* Chip Control Regs */
#define cr_cfg_idx    0x2e
#define cr_cfg_dat    0x2f

#define cr_cfg_idx2   0x4e
#define cr_cfg_dat2   0x4f

static u8 CFG_idx = cr_cfg_idx;
static u8 CFG_dat = cr_cfg_dat;

#define CHIP_ID_HIGH_ADDR 0x20
#define CHIP_ID_LOW_ADDR  0x21

#define CHIP_ID_HIGH 0xB4
#define CHIP_ID_LOW  0x73

#define ACTIVE_LOG_DEV   0x01
#define DEACTIVE_LOG_DEV 0x0

#define CIR_LOG_DEV 0x06

#define ACPI_LOG_DEV 0x0A

#define ENABLE_CIR_WAKE 0x08
#define DISABLE_CIR_WAKE 0xF7

#define ENABLE_CIR_INTR_OF_MOUSE_IRQ 0x80
#define DISABLE_CIR_INTR_OF_MOUSE_IRQ 0x7F

#define ENABLE_PME_INTR_OF_CIR_PASS 0x08
#define DISABLE_PME_INTR_OF_CIR_PASS 0xF7

#define CIR_WAKE_LOG_DEV 0x0E


/* read/update registers functions */

/* enter extended function mode */
static inline void cr_enter_ext(void);

/* exit extended function mode */
static inline void cr_exit_ext(void);

/* select logical device */
static inline void cr_select_log_dev(int cr);

static inline void cr_update(int dat, int cr);

static inline u8 cr_read(int cr);

/* update cr register without change other bits */
static inline void cr_safe_update(u8 dat, int cr);

/* clear cr register without change other bits */
static inline void cr_safe_clear(u8 dat, int cr);



/* read/write cir registers */

static inline void cir_update(u8 dat, int cir);

static u8 cir_read(int cir);

/* read/write cir wake registers */

static inline void cir_wake_update(u8 dat, int cir);

static u8 cir_wake_read(int cir);


/* dump current cir registers */
static void cir_dump_reg(void);

/* dump current cir wake up registers */
static void cir_wake_dump_reg(void);





/* driver module load/unload functions */

/* Config Registers init */
/*
 * initialize cr, cir, apci, cir wake logical devices
 * open these devices and irq
 */
static int w83667hg_cr_init(void);

/* Config Registers uninit */
/*
 * close cir and cir wake logical devices
 */
static void w83667hg_cr_uninit(void);


/* register input device (keyboard and mouse)
 *
 */

/* Define it for decoding keyboard and mouse in driver */
#define DECODE_KEYBOARD_MOUSE

/* this is the keycode table of US-EN layout keyboard
 * modify it to support other layout keyboard
 */
unsigned int usb_kbd_keycode[256] = {
	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
	 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
	 65, 66, 67, 68, 87, 88, 99, 70, 119, 110, 102, 104, 111, 107, 109, 106,
	105, 108, 103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
	 72, 73, 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190,
	191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, 136, 113,
	115, 114,  0,  0,  0, 121,  0, 89, 93, 124, 92, 94, 95,  0,  0,  0,
	122, 123, 90, 91, 85,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, 114, 113,
	150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140
};

/* input device name, locate in /sys/input/inputNUM/name */
static char *INPUTNAME = "MCE Remote Keyboard";

static struct input_id w83667hg_input_id = {
	.bustype = BUS_HOST, /* comunicate 667 by HOST, or I2C ? */
	.vendor  = 0x1050, /* Winbond PCI VENDOR ID */
	.product = 1, /* for basic devices, like keyboard & mouse */
	.version = 0, /* ignore it */
};


static int w83667hg_input_open(struct input_dev *cur_input_dev);

static void w83667hg_input_close(struct input_dev *cur_input_dev);

static struct input_dev *w83667hg_input_init(void);

static void w83667hg_input_uninit(struct input_dev *cur_input_dev);

/* internal call for register lirc */
static int lirc_set_use_inc(void *data);

static void lirc_set_use_dec(void *data);



static struct ir_recv_t {
	spinlock_t lock;
	u8 buf[IRCTL_BUF_LIMIT];
	unsigned int buf_count;
	wait_queue_head_t queue;
	/* for wake */
#define ST_WAKE_NONE      0x0
#define ST_WAKE_START     0x01
#define ST_WAKE_FINISH    0x02
	u8 wake_state;
	/* for recv */
#define ST_RECV_WAIT_7F    0x01
#define ST_RECV_WAIT_HEAD  0x02
#define ST_RECV_WAIT_SILENT_END  0x04
	u8 recv_state;
} w83667hg_ir_recv;

static struct ir_send_t {
	spinlock_t lock;
	u8 buf[IRCTL_BUF_LIMIT];
	unsigned int buf_count;
	unsigned int cur_buf_num;
	wait_queue_head_t queue;
	/* for send */
#define ST_SEND_NONE      0x0
#define ST_SEND_REQUEST   0x02
#define ST_SEND_REPLY     0x04
	u8 send_state;
} w83667hg_ir_send;

/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/
static struct input_dev *w83667hg_input_dev;

/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/
static struct lirc_driver *w83667hg_lirc_plugin;

#define LIRCBUF_SIZE 256

/* We initialise it at lirc_wb667_init() becuase of lirc group does not allow to initialise static varialbe to null.*/
static struct lirc_buffer *w83667hg_lirc_buffer;

static void w83667hg_ir_recv_init(struct ir_recv_t *ir_recv);

static void w83667hg_ir_send_init(struct ir_send_t *ir_send);

static int w83667hg_irctl_init(struct irctl *ir);

static void w83667hg_irctl_uninit(struct irctl *ir);




/* MCE CIR signal length, related on sample period */

/* MCE CIR controller signal length: about 43ms
 * 43ms / 50us (sample period) * 0.85 (inaccuracy)
 */
#define CONTROLLER_BUF_LEN_MIN 830

/* MCE CIR keyboard signal length: about 26ms
 * 26ms / 50us (sample period) * 0.85 (inaccuracy)
 */
#define KEYBOARD_BUF_LEN_MAX 650
#define KEYBOARD_BUF_LEN_MIN 610

/* MCE CIR mouse signal length: about 24ms
 * 24ms / 50us (sample period) * 0.85 (inaccuracy)
 */
#define MOUSE_BUF_LEN_MIN 565


#define CIR_SAMPLE_PERIOD 50
#define CIR_SAMPLE_LOW_INACCURACY 0.85


/* MAX silence time that driver will sent to lirc */
#define MAX_SILENCE_TIME 60000


/* fops */
/* set carrier frequency by ioctl IR_IOSETCARRIER
 *
 * that value can be get by ioctl value IR_IOGETCARRIER
 * on 667, set carrier on 2 registers: CP & CC
 * always set CP as 0x81
 * set CC by SPEC, CC = 3MHz/carrier - 1
 */
static int w83667hg_set_carrier(unsigned int *carrier);

static int lirc_ioctl(struct inode *node, struct file *filep, unsigned int cmd,
		unsigned long arg);

/* lirc_write
 *
 * 1) clean TX fifo first (handled by AP)
 * 2) copy data from user space
 * 3) open TX interrupt: TTR & TFU
 * 4) send 9 pulses to open TTR
 * in interrupt_handler:
 * 5) send all data out
 * go back to write():
 * 6) close TX interrupt
 *
 * The key problem of this function is user space data may larger than
 * driver's data buf length. So lirc_wirte() only copy IRCTL_BUF_LIMIT data to
 *  buf. And keep current copied data buf num in cur_buf_num. But driver's buf
 *  number may larger than TXFCONT (0xFF). So in interrupt_handler, it has to
 * set TXFCONT as 0xff, until buf_count less than 0xff.
 * The confustion is cur_buf_num in decode, study and send is designed on
 * different meaning.
 *
 */
static ssize_t lirc_write(struct file *file, const char *buf, size_t n, loff_t * ppos);



/* 1) clean lircdata and buf_count in irctl struct
 * 2) clean RX and TX fifo
 */
static void w83667hg_clean_data(struct ir_recv_t *ir_recv, struct irctl *ir);




/* send 1 recorded controller signal to lirc */
static void w83667hg_send_packet_to_lirc_1(struct irctl *ir, lirc_t *val);

/* this value copy from lirc_mod_mce */
#if CIR_IRCON_SAMPLE_PERIOD_SEL ==  CIR_IRCON_SAMPLE_PERIOD_SEL_100
	#define MCE_TIME_UNIT 100
#elif CIR_IRCON_SAMPLE_PERIOD_SEL ==  CIR_IRCON_SAMPLE_PERIOD_SEL_50
	#define MCE_TIME_UNIT 50
#elif CIR_IRCON_SAMPLE_PERIOD_SEL ==  CIR_IRCON_SAMPLE_PERIOD_SEL_25
	#define MCE_TIME_UNIT 25
#else
	#define MCE_TIME_UNIT 1
#endif

/* recode mce controller signal and send to lirc
 *
 * recode steps:
 * 1) high pulse, +128
 * 2) low pulse, do nothing
 * 3) keycode = pulse * 50
 * 4) sync head: PULSE_MASK (0xFF FFFF)
 * 5) 1, |PULSE_BIT (0x100 0000)
 *    0, +keycode
 *
 * function steps:
 * 0) clean lircdata[]
 * 1) jump head, put PULSE_BIT in lircdata[0]
 * 2) normal decode, "10"=>1 |PULSE_BIT
 *    save in lircdata[]
 * 3) send lircdata[] to lirc
 */
static void w83667hg_submit_controller(struct irctl *ir);


/* copy data from hardware fifo to driver buf
 *
 * 1. initial state is WAIT_7F
 * 2. if data is not 0x7f, copy data from hardware fifo to struct ir_recv buf
 * 3. if data is 0x7f, set recv_state as WAIT_HEAD, copy data from ir_recv to irctl
 * 4. depend on received buf length to select submit_ function
 * 5. set irctl buf len as 0
 * 5. receive data until data is not 0x7f, drop received 0x7f data, set recv_state as WAIT_7F again
 *
 * in normal, there are 3 parts in one infrared signal:
 * 1. not silent pulse      (ST_WAIT_7F)
 * 2. 0x7f silent pulse     (ST_WAIT_HEAD)
 * 3. silent pulse shorter than 0x7f   (ST_WAIT_HEAD)
 *
 * so this function copy signal part 1 and a 0x7f (for decode) to submit_() functions.
 * when receive 0x7f, this function copy data from ir_recv to irctl, and wait for next high pulse.
 */
static void w83667hg_recv(struct ir_recv_t *ir_recv, struct irctl *ir);


/* as VISTA MCE definition, valid carrier value */
#define MAX_CARRIER 60000
#define MIN_CARRIER 30000

/* receive function for STUDY
 *
 * 0. not receive 0x80, copy received data to ir_recv buf
 * when get 0x80, it means user released controller, and only need process received data
 * 1. get carrier
 * 2. get pulse
 */
static void w83667hg_study_recv(struct ir_recv_t *ir_recv, struct irctl *ir);

static irqreturn_t w83667hg_wake_interrupt_handler(int irq, void *dev);

static irqreturn_t w83667hg_interrupt_handler(int irq, void *dev);


/* pnp device */
#ifdef CONFIG_PNP


/* CIR and CIR WAKE */
static const struct pnp_device_id pnp_dev_table[] = {
	{ "WEC0530", 0 },   /* CIR */
	{ "NTN0530", 0 },   /* CIR for new chip's pnp id*/
	{ "", 0 },
};


MODULE_DEVICE_TABLE(pnp, pnp_dev_table);

static int __devinit lirc_wb667_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id);

static void __devexit lirc_wb667_pnp_remove(struct pnp_dev *dev);

/* before suspend
 * 1. set all states as NONE
 * 2. close CIR and WAKE interrupt
 * 3. close CIR and WAKE cr
 * 4. close input
 */
static int lirc_wb667_pnp_suspend(struct pnp_dev *dev, pm_message_t state);

/* resume all register and input device
 */
static int lirc_wb667_pnp_resume(struct pnp_dev *dev);

/* We initialise it as lirc_wb667_init because lirc group does not allow us to initialise static vaiable as 0 here. */
static unsigned int nopnp;

#else

/* We initialise it as lirc_lirc_wb667_init because lirc group does not allow us to initialise static vaiable as 0 here. */
static unsigned int nopnp;

#endif


/* create io region for cir and cir wake
 * create irq handler
 * create dev and data struct
 */
static int w83667hg_cir_probe(void);

/* uninit cir, cir wake, dev and data struct, release irq and io port */
static void w83667hg_cir_remove(void);


static int lirc_wb667_init(void);

void lirc_wb667_uninit(void);


/*
 * 1. init cr
 * 2. init input
 * 3. init lirc buffer, register, irctl
 * 4. init 667 cir dev, req_region, req_irq
 */
/*int init_module(void);
void cleanup_module(void);*/
int init_module_wb667(void);
void cleanup_module_wb667(void);

MODULE_DESCRIPTION("LIRC driver for Nuvoton W83667HG-A & W83677HG CIR");
MODULE_AUTHOR("Nuvoton PS Team");
MODULE_LICENSE("GPL");

/* device file name, locate in /dev/ directory */
/*//static char *DRVNAME = "w83667hg_ir";*/
/* FIXME, stable name*/
char *DRVNAME = "lirc_wb677";
module_param(DRVNAME, charp, S_IRUGO);
MODULE_PARM_DESC(DRVNAME, "Device file name in /dev/ and /sys/class/.");

/* platform driver name to register */
#define PLATNAME "lirc_wb677_cir"
#define PLATNAME_W "lirc_wb667_wake"

/* device file major number */
#define CIR_MAJOR 229

/* cir device base address */
static u16 CIR_BASE = 0x240;
module_param(CIR_BASE, ushort, S_IRUGO);
MODULE_PARM_DESC(CIR_BASE, "Base IO port address of 667/677 CIR device.");

/* cir base i/o address */
static unsigned int cir_address;

/* cir irq */
static ushort CIR_IRQ_NUM = 5;
module_param(CIR_IRQ_NUM, ushort, S_IRUGO);
MODULE_PARM_DESC(CIR_IRQ_NUM, "IRQ number for 667/677 CIR device.");

/* handle cir wake up request in driver or not */
#define ENABLE_CIR_WAKE_IRQ

/* cir wake up device base address */
static u16 CIR_WAKE_BASE = 0x250;
module_param(CIR_WAKE_BASE, ushort, S_IRUGO);
MODULE_PARM_DESC(CIR_WAKE_BASE, "Base IO port address of 667/677 CIR WAKE device.");

/* cir wake up base i/o address */
static unsigned int cir_wake_address;

/* cir wake up irq */
static ushort CIR_WAKE_IRQ_NUM = 5;
module_param(CIR_WAKE_IRQ_NUM, ushort, S_IRUGO);
MODULE_PARM_DESC(CIR_WAKE_IRQ_NUM, "IRQ number for 667/677 CIR WAKE device.");

/* nopnp option */
#ifdef CONFIG_PNP
module_param(nopnp, uint, S_IRUGO);
MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
#endif

/*//EXPORT_NO_SYMBOLS;*/