~ubuntu-branches/ubuntu/precise/linux-ti-omap/precise

« back to all changes in this revision

Viewing changes to ubuntu/lirc/lirc_wpc8769l/lirc_wpc8769l.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Bader, Amit Kucheria
  • Date: 2010-03-23 18:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20100323180512-iavj906ocnphdubp
Tags: 2.6.33-500.3
[ Amit Kucheria ]

* [Config] Fix the debug package name to end in -dbgsym
* SAUCE: Add the ubuntu/ drivers to omap
* SAUCE: Re-export the symbols for aufs
* [Config] Enable AUFS and COMPCACHE

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $Id: lirc_wpc8769l.c,v 1.8 2009/03/15 09:34:01 lirc Exp $      */
 
2
 
 
3
/****************************************************************************
 
4
 ** lirc_wpc8769l.c ****************************************************
 
5
 ****************************************************************************
 
6
 *
 
7
 * lirc_wpc8769l - Device driver for the integrated CIR receiver found in
 
8
 *                 Acer Aspire 6530G (and probably other models), based on
 
9
 *                 the Winbond 8769L embedded controller.
 
10
 *                 (Written using the lirc_serial driver as a guide).
 
11
 *
 
12
 * Copyright (C) 2008, 2009 Juan J. Garcia de Soria <skandalfo@gmail.com>
 
13
 *  This program is free software; you can redistribute it and/or modify
 
14
 *  it under the terms of the GNU General Public License as published by
 
15
 *  the Free Software Foundation; either version 2 of the License, or
 
16
 *  (at your option) any later version.
 
17
 *
 
18
 *  This program is distributed in the hope that it will be useful,
 
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 *  GNU General Public License for more details.
 
22
 *
 
23
 *  You should have received a copy of the GNU General Public License
 
24
 *  along with this program; if not, write to the Free Software
 
25
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
26
 *
 
27
 */
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
# include <config.h>
 
31
#endif
 
32
 
 
33
#include <linux/version.h>
 
34
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
 
35
#error "**********************************************************"
 
36
#error " Sorry, this driver needs kernel version 2.2.18 or higher "
 
37
#error "**********************************************************"
 
38
#endif
 
39
 
 
40
#include <linux/autoconf.h>
 
41
 
 
42
#include <linux/module.h>
 
43
#include <linux/errno.h>
 
44
#include <linux/fs.h>
 
45
#include <linux/interrupt.h>
 
46
#include <linux/ioport.h>
 
47
#include <linux/time.h>
 
48
#include <linux/timer.h>
 
49
#include <linux/types.h>
 
50
#include <linux/poll.h>
 
51
 
 
52
#include <linux/bitops.h>
 
53
 
 
54
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16)
 
55
#include <asm/io.h>
 
56
#else
 
57
#include <linux/io.h>
 
58
#endif
 
59
#include <linux/irq.h>
 
60
 
 
61
#include <linux/acpi.h>
 
62
 
 
63
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
 
64
#include <linux/platform_device.h>
 
65
#endif
 
66
 
 
67
#include "../lirc.h"
 
68
#include "../kcompat.h"
 
69
#include "../lirc_dev/lirc_dev.h"
 
70
 
 
71
#include "lirc_wpc8769l.h"
 
72
 
 
73
/* Name of the lirc device. */
 
74
#define LIRC_DRIVER_NAME "lirc_wpc8769l"
 
75
 
 
76
#define dprintk(fmt, args...)                                   \
 
77
        do {                                                    \
 
78
                if (debug)                                      \
 
79
                        printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
 
80
                               fmt, ## args);                   \
 
81
        } while (0)
 
82
 
 
83
#define wprintk(fmt, args...)                                   \
 
84
        do {                                                    \
 
85
                        printk(KERN_WARN LIRC_DRIVER_NAME ": "  \
 
86
                               fmt, ## args);                   \
 
87
        } while (0)
 
88
 
 
89
#define eprintk(fmt, args...)                                   \
 
90
        do {                                                    \
 
91
                        printk(KERN_ERR LIRC_DRIVER_NAME ": "   \
 
92
                               fmt, ## args);                   \
 
93
        } while (0)
 
94
 
 
95
#define iprintk(fmt, args...)                                   \
 
96
        do {                                                    \
 
97
                        printk(KERN_INFO LIRC_DRIVER_NAME ": "  \
 
98
                               fmt, ## args);                   \
 
99
        } while (0)
 
100
 
 
101
/* Number of driver->lirc-dev buffer elements. */
 
102
#define RBUF_LEN 256
 
103
 
 
104
/* Number of 0xff bytes received in a row. */
 
105
static unsigned int wpc8769l_ff_bytes_in_a_row;
 
106
 
 
107
/* Hardware resource parameters. */
 
108
static unsigned int baseport1;
 
109
static unsigned int baseport2;
 
110
static unsigned int irq;
 
111
 
 
112
/* Debugging flag. */
 
113
static int debug;
 
114
 
 
115
/* If true, we skip ACPI autodetection and use the parameter-supplied I/O and
 
116
 * IRQ. */
 
117
static int skip_probe;
 
118
 
 
119
/* Whether the device is open or not. */
 
120
static int lirc_wpc8769l_is_open;
 
121
 
 
122
/* Code disabled since it didn't seem to work with the test hardware. */
 
123
/*#define LIRC_WPC8769L_WAKEUP*/
 
124
#ifdef LIRC_WPC8769L_WAKEUP
 
125
/* These parameters are taken from the driver for MS Windows Vista.
 
126
 * The specific values used for your hardware may be found at this registry
 
127
 * key:
 
128
 *
 
129
 * HKEY_LOCAL_MACHINE/CurrentControlSet/Services/Winbond CIR/PowerKey
 
130
 */
 
131
static int protocol_select = 2;
 
132
static int max_info_bits = 24;
 
133
static unsigned int rc_wakeup_code = 0x7ffffbf3;
 
134
static unsigned int rc_wakeup_mask = 0xff000fff;
 
135
#endif
 
136
 
 
137
/* Resource allocation pointers. */
 
138
static struct resource *wpc8769l_portblock1_resource;
 
139
static struct resource *wpc8769l_portblock2_resource;
 
140
 
 
141
/* Hardware related spinlock. */
 
142
static DEFINE_SPINLOCK(wpc8769l_hw_spinlock);
 
143
 
 
144
/* The buffer for ISR to bottom half data transfer. */
 
145
static struct lirc_buffer rbuf;
 
146
 
 
147
/* Bit-to-MODE2 coalescing helper variables. */
 
148
static int last_was_pulse;
 
149
static lirc_t last_counter;
 
150
 
 
151
/* Microseconds after a timeout-triggered pulse. */
 
152
static s64 lastus;
 
153
 
 
154
/* Microseconds when the timer was started. */
 
155
static s64 timerstartus;
 
156
 
 
157
/* Put another pulse/space to the queue, checking for overruns. */
 
158
static void put_item(lirc_t data)
 
159
{
 
160
        if (lirc_buffer_full(&rbuf)) {
 
161
                if (printk_ratelimit())
 
162
                        eprintk("RX buffer overrun.\n");
 
163
                return;
 
164
        }
 
165
        lirc_buffer_write(&rbuf, (void *) &data);
 
166
}
 
167
 
 
168
/* Put any accumulated pulse/space to userspace. */
 
169
static void put_span(void)
 
170
{
 
171
        lirc_t data;
 
172
        if (last_counter) {
 
173
                /* Take the usecs length. */
 
174
                data = last_counter;
 
175
 
 
176
                /* Mark pulse or space. */
 
177
                if (last_was_pulse)
 
178
                        data |= PULSE_BIT;
 
179
 
 
180
                /* Put the span to the buffer. */
 
181
                put_item(data);
 
182
 
 
183
                /* Reset counter, in order to avoid emitting duplicate data. */
 
184
                last_counter = 0;
 
185
        }
 
186
}
 
187
 
 
188
/* Aggregate pulse time. */
 
189
static void put_pulse_bit(lirc_t n)
 
190
{
 
191
        if (last_was_pulse) {
 
192
                last_counter += n;
 
193
                if (last_counter > PULSE_MASK)
 
194
                        last_counter = PULSE_MASK;
 
195
        } else {
 
196
                put_span();
 
197
                last_was_pulse = 1;
 
198
                last_counter = n;
 
199
                if (last_counter > PULSE_MASK)
 
200
                        last_counter = PULSE_MASK;
 
201
        }
 
202
}
 
203
 
 
204
/* Aggregate space time. */
 
205
static void put_space_bit(lirc_t n)
 
206
{
 
207
        if (!last_was_pulse) {
 
208
                last_counter += n;
 
209
                if (last_counter > PULSE_MASK)
 
210
                        last_counter = PULSE_MASK;
 
211
        } else {
 
212
                put_span();
 
213
                last_was_pulse = 0;
 
214
                last_counter = n;
 
215
                if (last_counter > PULSE_MASK)
 
216
                        last_counter = PULSE_MASK;
 
217
        }
 
218
}
 
219
 
 
220
/* Timeout function for last pulse part. */
 
221
static void wpc8769l_last_timeout(unsigned long l)
 
222
{
 
223
        struct timeval currenttv;
 
224
 
 
225
        unsigned long flags;
 
226
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
227
 
 
228
        /* Mark the time at which we inserted the timeout span. */
 
229
        do_gettimeofday(&currenttv);
 
230
        lastus = ((s64) currenttv.tv_sec) * 1000000ll + currenttv.tv_usec;
 
231
 
 
232
        /* Emit the timeout as a space. */
 
233
        put_space_bit(lastus - timerstartus);
 
234
 
 
235
        /* Signal the bottom half wait queue
 
236
         * that there's data available. */
 
237
        wake_up_interruptible(&rbuf.wait_poll);
 
238
 
 
239
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
240
}
 
241
 
 
242
/* Timer for end-of-code pulse timeout. */
 
243
static struct timer_list last_span_timer =
 
244
        TIMER_INITIALIZER(wpc8769l_last_timeout, 0, 0);
 
245
 
 
246
/* Interrupt handler, doing the bit sample to mode2 conversion.
 
247
 * Perhaps this work should be taken outside of the ISR... */
 
248
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
 
249
static irqreturn_t irq_handler(int irqno, void *blah)
 
250
#else
 
251
static irqreturn_t irq_handler(int irqno, void *blah, struct pt_regs *regs)
 
252
#endif
 
253
{
 
254
        unsigned int data;
 
255
        int handled = 0;
 
256
        int count, more;
 
257
        struct timeval currenttv;
 
258
        s64 currentus, span;
 
259
 
 
260
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
 
261
        unsigned char data_buf[WPC8769L_BYTE_BUFFER_SIZE];
 
262
        unsigned char *data_ptr;
 
263
        unsigned long *ldata;
 
264
        unsigned int next_one, next_zero, size;
 
265
#else
 
266
        unsigned int mask;
 
267
#endif
 
268
 
 
269
        unsigned long flags;
 
270
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
271
 
 
272
        /* Check whether there's any data available. */
 
273
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
274
        data = inb(baseport1 + WPC8769L_DATA_STATUS_REG);
 
275
 
 
276
        if (data & WPC8769L_DATA_READY_MASK) {
 
277
                /* Get current timestamp. */
 
278
                do_gettimeofday(&currenttv);
 
279
                currentus = ((s64) currenttv.tv_sec) * 1000000ll +
 
280
                        currenttv.tv_usec;
 
281
 
 
282
                /* If we had a timeout before we might need to fill
 
283
                 * in additional space time. */
 
284
                if (lastus) {
 
285
                        /* Calculate the difference, compensating
 
286
                         * the time for the data successfully
 
287
                         * received (estimated to be
 
288
                         * WPC8769L_BYTES_PER_BURST bytes). */
 
289
                        span = currentus - lastus
 
290
                                        - WPC8769L_BYTES_PER_BURST
 
291
                                        * WPC8769L_USECS_PER_BYTE;
 
292
 
 
293
                        /* Only insert positive spans. */
 
294
                        if (span > 0) {
 
295
                                /* Emit the extended gap as a space. */
 
296
                                put_space_bit(span);
 
297
                        }
 
298
 
 
299
                        /* Mark that we had the last timeout into account. */
 
300
                        lastus = 0;
 
301
                }
 
302
 
 
303
                count = 0;
 
304
                more = 1;
 
305
 
 
306
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
 
307
                data_ptr = data_buf;
 
308
#endif
 
309
                do {
 
310
                        /* Read the next byte of data. */
 
311
                        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
312
                        data = inb(baseport1 + WPC8769L_DATA_REG);
 
313
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
 
314
                        *data_ptr++ = data;
 
315
#else
 
316
                        for (mask = 0x01 ; mask < 0x100; mask <<= 1) {
 
317
                                if (data & mask)
 
318
                                        put_space_bit(WPC8769L_USECS_PER_BIT);
 
319
                                else
 
320
                                        put_pulse_bit(WPC8769L_USECS_PER_BIT);
 
321
                        }
 
322
#endif
 
323
 
 
324
                        /* Check for 0xff in a row. */
 
325
                        if (data == 0xff)
 
326
                                wpc8769l_ff_bytes_in_a_row++;
 
327
                        else
 
328
                                wpc8769l_ff_bytes_in_a_row = 0;
 
329
 
 
330
                        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
331
                        data = inb(baseport1 + WPC8769L_DATA_ACK_REG);
 
332
                        if (data & WPC8769L_DATA_ACK_REG) {
 
333
                                outb(WPC8769L_BANK_E0,
 
334
                                        baseport1 + WPC8769L_SELECT_REG);
 
335
                                data = inb(baseport1 +
 
336
                                        WPC8769L_REMAINING_RX_DATA_REG);
 
337
                                if (!data)
 
338
                                        more = 0;
 
339
                        } else
 
340
                                more = 0;
 
341
 
 
342
                        count++;
 
343
                } while (more && count < WPC8769L_BYTES_PER_BURST);
 
344
 
 
345
                if (wpc8769l_ff_bytes_in_a_row
 
346
                        >= WPC8769L_FF_BYTES_BEFORE_RESET) {
 
347
 
 
348
                        /* Put in another 0xff byte. */
 
349
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
 
350
                        *data_ptr++ = 0xff;
 
351
                        count++;
 
352
#else
 
353
                        put_space_bit(8 * WPC8769L_USECS_PER_BIT);
 
354
#endif
 
355
 
 
356
                        /* Reset the hardware in the case of too many
 
357
                         * 0xff bytes in a row. */
 
358
                        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
359
                        outb(WPC8769L_TIMEOUT_RESET_MASK,
 
360
                                baseport1 + WPC8769L_TIMEOUT_RESET_REG);
 
361
                }
 
362
 
 
363
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
 
364
                /* Emit the data. */
 
365
                size = count << 3;
 
366
 
 
367
                ldata = (unsigned long *) data_buf;
 
368
                next_one = generic_find_next_le_bit(ldata, size, 0);
 
369
 
 
370
                if (next_one > 0)
 
371
                        put_pulse_bit(next_one
 
372
                                * WPC8769L_USECS_PER_BIT);
 
373
 
 
374
                while (next_one < size) {
 
375
                        next_zero = generic_find_next_zero_le_bit(ldata,
 
376
                                size, next_one + 1);
 
377
 
 
378
                        put_space_bit(
 
379
                                (next_zero - next_one)
 
380
                                * WPC8769L_USECS_PER_BIT);
 
381
 
 
382
                        if (next_zero < size) {
 
383
                                next_one = generic_find_next_le_bit(ldata,
 
384
                                        size, next_zero + 1);
 
385
 
 
386
                                put_pulse_bit(
 
387
                                        (next_one - next_zero)
 
388
                                        * WPC8769L_USECS_PER_BIT);
 
389
                        } else {
 
390
                                next_one = size;
 
391
                        }
 
392
                }
 
393
#endif
 
394
 
 
395
                /* Mark the IRQ as handled. */
 
396
                handled = 1;
 
397
 
 
398
                /* Signal the bottom half wait queue
 
399
                 * that there's data available. */
 
400
                wake_up_interruptible(&rbuf.wait_poll);
 
401
 
 
402
                /* Set up timeout handling. */
 
403
                mod_timer(&last_span_timer,
 
404
                        jiffies + WPC8769L_LAST_TIMEOUT_JIFFIES);
 
405
 
 
406
                /* Set up last timer us mark. */
 
407
                timerstartus = currentus;
 
408
        }
 
409
 
 
410
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
411
        return IRQ_RETVAL(handled);
 
412
}
 
413
 
 
414
/* Prepare the hardware on module load. */
 
415
static void wpc8769l_prepare_hardware(void)
 
416
{
 
417
        unsigned long flags;
 
418
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
419
 
 
420
        /* I don't know why this needs reading. */
 
421
        outb(WPC8769L_BANK_E4, baseport1 + WPC8769L_SELECT_REG);
 
422
        inb(baseport1 + WPC8769L_READ_ON_STARTUP_REG);
 
423
 
 
424
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
425
}
 
426
 
 
427
 
 
428
/* Wake up device from power down and check whether it was the
 
429
 * device that woke us up.
 
430
 */
 
431
static int wpc8769l_power_up_and_check_if_we_woke_us_up(void)
 
432
{
 
433
        unsigned int data;
 
434
        int res;
 
435
 
 
436
        unsigned long flags;
 
437
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
438
 
 
439
        if (baseport2) {
 
440
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
441
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
442
                data |= WPC8769L_CLOCK_ON_MASK;
 
443
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
444
 
 
445
                res = inb(baseport2 + WPC8769L_WAKEUP_STATUS_REG)
 
446
                        & WPC8769L_WAKEUP_WOKE_UP_MASK;
 
447
 
 
448
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
449
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
450
                data |= WPC8769L_CLOCK_ON_MASK;
 
451
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
452
 
 
453
                outb(WPC8769L_WAKEUP_WOKE_UP_MASK,
 
454
                        baseport2 + WPC8769L_WAKEUP_STATUS_REG);
 
455
 
 
456
                outb(WPC8769L_WAKEUP_ACK_MASK,
 
457
                        baseport2 + WPC8769L_WAKEUP_ACK_REG);
 
458
        } else {
 
459
                outb(WPC8769L_BANK_F0, baseport1 + WPC8769L_SELECT_REG);
 
460
                res = (inb(baseport1 + WPC8769L_WAKEUP_STATUS_LEG_REG)
 
461
                        & WPC8769L_WAKEUP_STATUS_LEG_MASK) ? 1 : 0;
 
462
        }
 
463
 
 
464
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
465
 
 
466
        return res;
 
467
}
 
468
 
 
469
/* Disable interrupts from device. */
 
470
static void wpc8769l_disable_interrupts(void)
 
471
{
 
472
        unsigned long flags;
 
473
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
474
 
 
475
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
476
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
477
        outb(inb(baseport1 + WPC8769L_INTERRUPT_REG)
 
478
                & ~WPC8769L_INTERRUPT_1_MASK,
 
479
                baseport1 + WPC8769L_INTERRUPT_REG);
 
480
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
481
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
482
        outb(inb(baseport1 + WPC8769L_INTERRUPT_REG)
 
483
                & ~WPC8769L_INTERRUPT_1_MASK,
 
484
                baseport1 + WPC8769L_INTERRUPT_REG);
 
485
 
 
486
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
487
}
 
488
 
 
489
#ifdef LIRC_WPC8769L_WAKEUP
 
490
/* Expand value nibble for configuration of wake up parameters.
 
491
 * This seems to manchester-encode a nibble into a byte. */
 
492
static unsigned int wpc8769l_expand_value_nibble(unsigned int nibble)
 
493
{
 
494
        int i;
 
495
        unsigned int tmp, tmp2, res;
 
496
 
 
497
        res = 0;
 
498
 
 
499
        for (i = 0; i < 4; i += 2) {
 
500
                tmp = (nibble >> i) & 0x3;
 
501
                switch (tmp) {
 
502
                case 3:
 
503
                        tmp2 = 5;
 
504
                        break;
 
505
                case 2:
 
506
                        tmp2 = 6;
 
507
                        break;
 
508
                case 1:
 
509
                        tmp2 = 9;
 
510
                        break;
 
511
                case 0:
 
512
                        tmp2 = 0x0a;
 
513
                        break;
 
514
                default:
 
515
                        return 0;
 
516
                        break;
 
517
                }
 
518
                res |= ((tmp2 << i) << i);
 
519
        }
 
520
 
 
521
        return res;
 
522
}
 
523
 
 
524
/* Expand mask nibble for configuration of wake up parameters. */
 
525
static unsigned int wpc8769l_expand_mask_nibble(unsigned int nibble)
 
526
{
 
527
        int i;
 
528
        unsigned int tmp, tmp2, res;
 
529
 
 
530
        res = 0;
 
531
 
 
532
        for (i = 0; i < 4; i += 2) {
 
533
                tmp = (nibble >> i) & 0x3;
 
534
                switch (tmp) {
 
535
                case 0:
 
536
                        tmp2 = 0;
 
537
                        break;
 
538
                case 1:
 
539
                        tmp2 = 3;
 
540
                        break;
 
541
                case 2:
 
542
                        tmp2 = 0x0c;
 
543
                        break;
 
544
                case 3:
 
545
                        tmp2 = 0x0f;
 
546
                        break;
 
547
                default:
 
548
                        return 0;
 
549
                        break;
 
550
                }
 
551
                res |= ((tmp2 << i) << i);
 
552
        }
 
553
 
 
554
        return res;
 
555
}
 
556
 
 
557
/* Configure wake up triggers for the hardware that supports it.
 
558
 * THE CALLER MUST HAVE ACQUIRED wpc8769l_hw_spinlock BEFORE CALLING.
 
559
 */
 
560
static void wpc8769l_configure_wakeup_triggers(void)
 
561
{
 
562
        unsigned int x;
 
563
        unsigned int data, data2;
 
564
 
 
565
        int i, j;
 
566
 
 
567
        x = inb(baseport2 + WPC8769L_WAKEUP_ENABLE_REG)
 
568
                & WPC8769L_WAKEUP_ENABLE_MASK;
 
569
        outb(inb(baseport2 + WPC8769L_WAKEUP_ENABLE_REG)
 
570
                & ~WPC8769L_WAKEUP_ENABLE_MASK,
 
571
                baseport2 + WPC8769L_WAKEUP_ENABLE_REG);
 
572
 
 
573
        data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
574
        data &= ~WPC8769L_CLOCK_OFF_MASK;
 
575
        data |= WPC8769L_CLOCK_ON_MASK;
 
576
        outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
577
 
 
578
        outb(WPC8769L_WAKEUP_CONFIGURING_MASK,
 
579
                baseport2 + WPC8769L_WAKEUP_STATUS_REG);
 
580
        outb(WPC8769L_WAKEUP_ACK_MASK,
 
581
                baseport2 + WPC8769L_WAKEUP_ACK_REG);
 
582
 
 
583
        data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
584
        data &= ~WPC8769L_CLOCK_OFF_MASK;
 
585
        data |= WPC8769L_CLOCK_ON_MASK;
 
586
        outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
587
 
 
588
        data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
589
        data &= ~WPC8769L_CLOCK_OFF_MASK;
 
590
        data |= WPC8769L_CLOCK_ON_MASK;
 
591
        outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
592
 
 
593
        data = inb(baseport2 + WPC8769L_WAKEUP_CONFIG_REG);
 
594
        data &= WPC8769L_WAKEUP_CONFIG_PRE_MASK;
 
595
        data |= (max_info_bits + WPC8769L_MAX_INFO_BITS_BIAS)
 
596
                << WPC8769L_MAX_INFO_BITS_SHIFT;
 
597
        outb(data, baseport2 + WPC8769L_WAKEUP_CONFIG_REG);
 
598
 
 
599
        i = j = 0;
 
600
 
 
601
        /* Program values. */
 
602
        while (j < WPC8769L_WAKEUP_DATA_BITS) {
 
603
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
604
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
605
                data |= WPC8769L_CLOCK_ON_MASK;
 
606
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
607
 
 
608
                outb(i + WPC8769L_WAKEUP_DATA_BASE,
 
609
                        baseport2 + WPC8769L_WAKEUP_DATA_PTR_REG);
 
610
 
 
611
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
612
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
613
                data |= WPC8769L_CLOCK_ON_MASK;
 
614
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
615
 
 
616
                data = (rc_wakeup_code >> j) & 0x0f;
 
617
                data = wpc8769l_expand_value_nibble(data);
 
618
                outb(data, baseport2 + WPC8769L_WAKEUP_DATA_REG);
 
619
 
 
620
                i++;
 
621
                j += 4;
 
622
        }
 
623
 
 
624
        /* Program masks. */
 
625
        while (j < WPC8769L_WAKEUP_DATA_BITS) {
 
626
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
627
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
628
                data |= WPC8769L_CLOCK_ON_MASK;
 
629
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
630
 
 
631
                outb(i + WPC8769L_WAKEUP_MASK_BASE,
 
632
                        baseport2 + WPC8769L_WAKEUP_DATA_PTR_REG);
 
633
 
 
634
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
635
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
636
                data |= WPC8769L_CLOCK_ON_MASK;
 
637
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
638
 
 
639
                data = (rc_wakeup_mask >> j) & 0x0f;
 
640
                data = wpc8769l_expand_mask_nibble(data);
 
641
                outb(data, baseport2 + WPC8769L_WAKEUP_DATA_REG);
 
642
 
 
643
                i++;
 
644
                j += 4;
 
645
        }
 
646
 
 
647
        data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
648
        data &= ~WPC8769L_CLOCK_OFF_MASK;
 
649
        data |= WPC8769L_CLOCK_ON_MASK;
 
650
        outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
651
 
 
652
        data2 = inb(baseport2 + WPC8769L_WAKEUP_CONFIG2_REG);
 
653
        data2 &= WPC8769L_WAKEUP_CONFIG2_AND_MASK;
 
654
        data2 |= WPC8769L_WAKEUP_CONFIG2_OR_MASK;
 
655
 
 
656
        data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
657
        data &= ~WPC8769L_CLOCK_OFF_MASK;
 
658
        data |= WPC8769L_CLOCK_ON_MASK;
 
659
        outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
660
 
 
661
        outb(data2, baseport2 + WPC8769L_WAKEUP_CONFIG2_REG);
 
662
 
 
663
        if (x != WPC8769L_WAKEUP_ENABLE_MASK)
 
664
                outb(inb(baseport2 + WPC8769L_WAKEUP_ENABLE_REG)
 
665
                | WPC8769L_WAKEUP_ENABLE_MASK,
 
666
                baseport2 + WPC8769L_WAKEUP_ENABLE_REG);
 
667
}
 
668
#endif
 
669
 
 
670
/* Enable interrupts from device. */
 
671
static void wpc8769l_enable_interrupts(void)
 
672
{
 
673
        unsigned int data, data2, data_save;
 
674
 
 
675
        unsigned int a, b;
 
676
 
 
677
        unsigned long flags;
 
678
        spin_lock_irqsave(&wpc8769l_hw_spinlock, flags);
 
679
 
 
680
        outb(WPC8769L_BANK_F0, baseport1 + WPC8769L_SELECT_REG);
 
681
        data_save = inb(baseport1 + WPC8769L_WAKEUP_STATUS_LEG_REG);
 
682
 
 
683
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
684
        outb(0, baseport1 + WPC8769L_HARDWARE_ENABLE1_REG);
 
685
 
 
686
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
687
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
688
        outb(inb(baseport1 + WPC8769L_HARDWARE_ENABLE1_REG)
 
689
                | WPC8769L_HARDWARE_ENABLE1_MASK,
 
690
                baseport1 + WPC8769L_HARDWARE_ENABLE1_REG);
 
691
 
 
692
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
693
        outb(0, baseport1 + WPC8769L_CONFIG_REG);
 
694
 
 
695
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
696
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
697
        data = inb(baseport1 + WPC8769L_CONFIG_REG);
 
698
        data &= ~WPC8769L_CONFIG_OFF_MASK;
 
699
        data |= WPC8769L_CONFIG_ON_MASK;
 
700
        outb(data, baseport1 + WPC8769L_CONFIG_REG);
 
701
 
 
702
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
703
        outb(WPC8769L_DATA_STATUS_MASK_1, baseport1 + WPC8769L_DATA_STATUS_REG);
 
704
 
 
705
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
706
        outb(WPC8769L_DATA_STATUS_MASK_2, baseport1 + WPC8769L_DATA_STATUS_REG);
 
707
 
 
708
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
709
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
710
        outb(inb(baseport1 + WPC8769L_CONFIG2_REG)
 
711
                & ~WPC8769L_CONFIG2_OFF_MASK,
 
712
                baseport1 + WPC8769L_CONFIG2_REG);
 
713
 
 
714
        outb(WPC8769L_BANK_EC, baseport1 + WPC8769L_SELECT_REG);
 
715
        outb(WPC8769L_BANK_EC, baseport1 + WPC8769L_SELECT_REG);
 
716
        outb(inb(baseport1 + WPC8769L_CONFIG3_REG)
 
717
                | WPC8769L_CONFIG3_ON_MASK,
 
718
                baseport1 + WPC8769L_CONFIG3_REG);
 
719
 
 
720
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
721
        data = inb(baseport1 + WPC8769L_CONFIG4_REG);
 
722
        data &= WPC8769L_CONFIG4_AND_MASK;
 
723
        data |= WPC8769L_CONFIG4_ON_MASK;
 
724
 
 
725
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
726
        outb(data, baseport1 + WPC8769L_CONFIG4_REG);
 
727
 
 
728
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
729
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
730
        outb(inb(baseport1 + WPC8769L_CONFIG5_REG)
 
731
                | WPC8769L_CONFIG5_ON_MASK,
 
732
                baseport1 + WPC8769L_CONFIG5_REG);
 
733
 
 
734
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
735
        outb(WPC8769L_CONFIG6_MASK, baseport1 + WPC8769L_CONFIG6_REG);
 
736
 
 
737
        outb(WPC8769L_BANK_E0, baseport1 + WPC8769L_SELECT_REG);
 
738
        outb(0, baseport1 + WPC8769L_CONFIG7_REG);
 
739
 
 
740
        if (baseport2) {
 
741
                /*
 
742
                 * This has to do with wake-up support, which is
 
743
                 * disabled when the second I/O range doesn't
 
744
                 * exist.
 
745
                 */
 
746
                /* -- internal subroutine -- */
 
747
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
748
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
749
                data |= WPC8769L_CLOCK_ON_MASK;
 
750
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
751
 
 
752
                data2 = inb(baseport2 + WPC8769L_WAKEUP_CONFIG3_REG);
 
753
                a = (data2 >> WPC8769L_WAKEUP_CONFIG3_A_SHIFT)
 
754
                        & WPC8769L_WAKEUP_CONFIG3_A_MASK;
 
755
                b = (data2 >> WPC8769L_WAKEUP_CONFIG3_B_SHIFT)
 
756
                        & WPC8769L_WAKEUP_CONFIG3_B_MASK;
 
757
 
 
758
                data = inb(baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
759
                data &= ~WPC8769L_CLOCK_OFF_MASK;
 
760
                data |= WPC8769L_CLOCK_ON_MASK;
 
761
                outb(data, baseport2 + WPC8769L_BANK2_CLOCK_REG);
 
762
 
 
763
                data2 &= ~WPC8769L_WAKEUP_CONFIG3_OFF_MASK;
 
764
                data2 |= WPC8769L_WAKEUP_CONFIG3_ON_MASK;
 
765
                outb(data2, baseport2 + WPC8769L_WAKEUP_CONFIG3_REG);
 
766
                /* -- end internal subroutine -- */
 
767
 
 
768
#ifdef LIRC_WPC8769L_WAKEUP
 
769
                /* Call for setting wake up filters */
 
770
                wpc8769l_configure_wakeup_triggers();
 
771
#endif
 
772
        } else {
 
773
                /* No second port range. Take these defaults. */
 
774
                a = (data_save & WPC8769L_WAKEUP_STATUS_LEG_MASK_A)
 
775
                        ? 0 : 1;
 
776
                b = (data_save & WPC8769L_WAKEUP_STATUS_LEG_MASK_B)
 
777
                        ? 1 : 0;
 
778
        }
 
779
 
 
780
        outb(WPC8769L_BANK_EC, baseport1 + WPC8769L_SELECT_REG);
 
781
        outb(WPC8769L_BANK_EC, baseport1 + WPC8769L_SELECT_REG);
 
782
 
 
783
        data = inb(baseport1 + WPC8769L_CONFIG3_REG);
 
784
        data = (a == 1)
 
785
                ? (data & ~WPC8769L_CONFIG3_MASK_1)
 
786
                : (data | WPC8769L_CONFIG3_MASK_1);
 
787
        outb(data, baseport1 + WPC8769L_CONFIG3_REG);
 
788
 
 
789
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
790
        outb(WPC8769L_BANK_F4, baseport1 + WPC8769L_SELECT_REG);
 
791
 
 
792
        data = inb(baseport1 + WPC8769L_CONFIG2_REG);
 
793
        data = (b == 0)
 
794
                ? (data & ~WPC8769L_CONFIG2_MASK_1)
 
795
                : (data | WPC8769L_CONFIG2_MASK_1);
 
796
        outb(data, baseport1 + WPC8769L_CONFIG2_REG);
 
797
 
 
798
        outb(0, baseport1 + WPC8769L_CONFIG8_REG);
 
799
 
 
800
        outb(0, baseport1 + WPC8769L_CONFIG9_REG);
 
801
 
 
802
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
803
        outb(WPC8769L_BANK_00, baseport1 + WPC8769L_SELECT_REG);
 
804
        outb(inb(baseport1 + WPC8769L_INTERRUPT_REG)
 
805
                | WPC8769L_INTERRUPT_1_MASK,
 
806
                baseport1 + WPC8769L_INTERRUPT_REG);
 
807
 
 
808
        spin_unlock_irqrestore(&wpc8769l_hw_spinlock, flags);
 
809
}
 
810
 
 
811
/* Called when the device is opened. */
 
812
static int set_use_inc(void *data)
 
813
{
 
814
        int result;
 
815
 
 
816
        /* Reset pulse values. */
 
817
        last_was_pulse = 0;
 
818
        last_counter = 0;
 
819
 
 
820
        /* Reset last timeout value. */
 
821
        lastus = 0;
 
822
 
 
823
        /* Init the read buffer. */
 
824
        if (lirc_buffer_init(&rbuf, sizeof(lirc_t), RBUF_LEN) < 0)
 
825
                return -ENOMEM;
 
826
 
 
827
        /* Acquire the IRQ. */
 
828
        result = request_irq(irq, irq_handler,
 
829
                           IRQF_DISABLED | IRQF_SHARED,
 
830
                           LIRC_DRIVER_NAME, THIS_MODULE);
 
831
 
 
832
        switch (result) {
 
833
        case -EBUSY:
 
834
                eprintk("IRQ %d busy\n", irq);
 
835
                lirc_buffer_free(&rbuf);
 
836
                return -EBUSY;
 
837
        case -EINVAL:
 
838
                eprintk("Bad irq number or handler\n");
 
839
                lirc_buffer_free(&rbuf);
 
840
                return -EINVAL;
 
841
        default:
 
842
                dprintk("IRQ %d obtained.\n", irq);
 
843
                break;
 
844
        };
 
845
 
 
846
        /* Mark the device as open. */
 
847
        lirc_wpc8769l_is_open = 1;
 
848
 
 
849
        /* Enable hardware interrupts. */
 
850
        wpc8769l_enable_interrupts();
 
851
 
 
852
        MOD_INC_USE_COUNT;
 
853
        return 0;
 
854
}
 
855
 
 
856
/* Called when the device is released. */
 
857
static void set_use_dec(void *data)
 
858
{
 
859
        /* Mark the device as closed. */
 
860
        lirc_wpc8769l_is_open = 0;
 
861
 
 
862
        /* Cancel the timeout if pending. */
 
863
        del_timer_sync(&last_span_timer);
 
864
 
 
865
        /* Disable the hardware interrupts. */
 
866
        wpc8769l_disable_interrupts();
 
867
 
 
868
        /* Free the IRQ. */
 
869
        free_irq(irq, THIS_MODULE);
 
870
        dprintk("Freed IRQ %d\n", irq);
 
871
 
 
872
        /* Free the RX buffer. */
 
873
        lirc_buffer_free(&rbuf);
 
874
 
 
875
        MOD_DEC_USE_COUNT;
 
876
}
 
877
 
 
878
static struct lirc_driver driver = {
 
879
        .name           = LIRC_DRIVER_NAME,
 
880
        .minor          = -1,
 
881
        .code_length    = 1,
 
882
        .sample_rate    = 0,
 
883
        .data           = NULL,
 
884
        .add_to_buf     = NULL,
 
885
        .get_queue      = NULL,
 
886
        .rbuf           = &rbuf,
 
887
        .set_use_inc    = set_use_inc,
 
888
        .set_use_dec    = set_use_dec,
 
889
        .fops           = NULL,
 
890
        .dev            = NULL,
 
891
        .owner          = THIS_MODULE,
 
892
};
 
893
 
 
894
static acpi_status wec_parse_resources(struct acpi_resource *resource,
 
895
        void *context)
 
896
{
 
897
        if (resource->type == ACPI_RESOURCE_TYPE_IO) {
 
898
                /* Read the two I/O ranges. */
 
899
                if (!baseport1)
 
900
                        baseport1 = resource->data.io.minimum;
 
901
                else if (!baseport2)
 
902
                        baseport2 = resource->data.io.minimum;
 
903
        } else if (resource->type == ACPI_RESOURCE_TYPE_IRQ) {
 
904
                /* Read the rx IRQ number. */
 
905
                if (!irq)
 
906
                        irq = resource->data.irq.interrupts[0];
 
907
        }
 
908
        return AE_OK;
 
909
}
 
910
 
 
911
static acpi_status wec_parse_device(acpi_handle handle, u32 level,
 
912
        void *context, void **return_value)
 
913
{
 
914
        acpi_status status;
 
915
        iprintk("Found %s device via ACPI.\n", WPC8769L_ACPI_HID);
 
916
 
 
917
        status = acpi_walk_resources(handle, METHOD_NAME__CRS,
 
918
                wec_parse_resources, NULL);
 
919
        if (ACPI_FAILURE(status))
 
920
                return status;
 
921
 
 
922
        return AE_OK;
 
923
}
 
924
 
 
925
/* Find the device I/O ranges and IRQ number by searching for the
 
926
 * CIR ACPI entry. */
 
927
static int wpc8769l_acpi_detect(void)
 
928
{
 
929
        acpi_status status;
 
930
        status = acpi_get_devices(WPC8769L_ACPI_HID, wec_parse_device, NULL,
 
931
                NULL);
 
932
        if (ACPI_FAILURE(status))
 
933
                return -ENOENT;
 
934
        else
 
935
                return 0;
 
936
}
 
937
 
 
938
#ifdef MODULE
 
939
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
 
940
static struct platform_device *lirc_wpc8769l_platform_dev;
 
941
 
 
942
static int __devinit lirc_wpc8769l_probe(struct platform_device *dev)
 
943
{
 
944
        return 0;
 
945
}
 
946
 
 
947
static int __devexit lirc_wpc8769l_remove(struct platform_device *dev)
 
948
{
 
949
        return 0;
 
950
}
 
951
 
 
952
static int lirc_wpc8769l_suspend(struct platform_device *dev,
 
953
                               pm_message_t state)
 
954
{
 
955
        if (lirc_wpc8769l_is_open)
 
956
                /* Disable all interrupts. */
 
957
                wpc8769l_disable_interrupts();
 
958
        return 0;
 
959
}
 
960
 
 
961
static int lirc_wpc8769l_resume(struct platform_device *dev)
 
962
{
 
963
        if (lirc_wpc8769l_is_open) {
 
964
                /* Check if we caused resuming; we still do nothing about it. */
 
965
                wpc8769l_power_up_and_check_if_we_woke_us_up();
 
966
 
 
967
                /* Enable interrupts again. */
 
968
                wpc8769l_enable_interrupts();
 
969
        }
 
970
        return 0;
 
971
}
 
972
 
 
973
static struct platform_driver lirc_wpc8769l_platform_driver = {
 
974
        .probe          = lirc_wpc8769l_probe,
 
975
        .remove         = __devexit_p(lirc_wpc8769l_remove),
 
976
        .suspend        = lirc_wpc8769l_suspend,
 
977
        .resume         = lirc_wpc8769l_resume,
 
978
        .driver         = {
 
979
                .name   = LIRC_DRIVER_NAME,
 
980
                .owner  = THIS_MODULE,
 
981
        },
 
982
};
 
983
 
 
984
static int __init lirc_wpc8769l_platform_init(void)
 
985
{
 
986
        int result;
 
987
 
 
988
        result = platform_driver_register(&lirc_wpc8769l_platform_driver);
 
989
        if (result) {
 
990
                eprintk("Platform driver register returned %d.\n", result);
 
991
                return result;
 
992
        }
 
993
 
 
994
        lirc_wpc8769l_platform_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
 
995
        if (!lirc_wpc8769l_platform_dev) {
 
996
                result = -ENOMEM;
 
997
                goto exit_driver_unregister;
 
998
        }
 
999
 
 
1000
        result = platform_device_add(lirc_wpc8769l_platform_dev);
 
1001
        if (result)
 
1002
                goto exit_device_put;
 
1003
 
 
1004
        return 0;
 
1005
 
 
1006
exit_device_put:
 
1007
        platform_device_put(lirc_wpc8769l_platform_dev);
 
1008
 
 
1009
exit_driver_unregister:
 
1010
        platform_driver_unregister(&lirc_wpc8769l_platform_driver);
 
1011
        return result;
 
1012
}
 
1013
 
 
1014
static void __exit lirc_wpc8769l_platform_exit(void)
 
1015
{
 
1016
        platform_device_unregister(lirc_wpc8769l_platform_dev);
 
1017
        platform_driver_unregister(&lirc_wpc8769l_platform_driver);
 
1018
}
 
1019
#endif
 
1020
 
 
1021
static int __init lirc_wpc8769l_module_init(void)
 
1022
{
 
1023
        int rc;
 
1024
 
 
1025
        /* If needed, read the resource information for the ACPI device
 
1026
         * description. */
 
1027
        if (!skip_probe) {
 
1028
                rc = wpc8769l_acpi_detect();
 
1029
                if (rc) {
 
1030
                        eprintk("Error when looking for %s ACPI device.\n",
 
1031
                                WPC8769L_ACPI_HID);
 
1032
                        return rc;
 
1033
                }
 
1034
        }
 
1035
 
 
1036
        /* Check that we got some resource info to work with. */
 
1037
        if (!baseport1 || !irq) {
 
1038
                rc = -ENODEV;
 
1039
                eprintk("Not all required resources found for %s device.\n",
 
1040
                        LIRC_DRIVER_NAME);
 
1041
                return rc;
 
1042
        }
 
1043
 
 
1044
        dprintk("%s device found to use 0x%04x, 0x%04x I/O bases, IRQ #%d.\n",
 
1045
                LIRC_DRIVER_NAME, baseport1, baseport2, irq);
 
1046
 
 
1047
        /* Request the two I/O regions. */
 
1048
        wpc8769l_portblock1_resource = request_region(baseport1,
 
1049
                WPC8769L_IO_REGION_1_SIZE, LIRC_DRIVER_NAME);
 
1050
        if (!wpc8769l_portblock1_resource) {
 
1051
                rc = -EBUSY;
 
1052
                eprintk("Could not allocate I/O range at 0x%04x", baseport1);
 
1053
                return rc;
 
1054
        }
 
1055
        if (baseport2) {
 
1056
                wpc8769l_portblock2_resource = request_region(baseport2,
 
1057
                        WPC8769L_IO_REGION_2_SIZE, LIRC_DRIVER_NAME);
 
1058
                if (!wpc8769l_portblock2_resource) {
 
1059
                        rc = -EBUSY;
 
1060
                        printk(KERN_ERR "Could not allocate I/O range "
 
1061
                               "at 0x%04x",
 
1062
                                baseport2);
 
1063
                        goto exit_release_region_1;
 
1064
                }
 
1065
        }
 
1066
 
 
1067
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
 
1068
        /* Register the platform driver and device. */
 
1069
        rc = lirc_wpc8769l_platform_init();
 
1070
        if (rc)
 
1071
                goto exit_release_region_2;
 
1072
#endif
 
1073
 
 
1074
        /* Prepare the hardware. */
 
1075
        wpc8769l_prepare_hardware();
 
1076
 
 
1077
        /* Do load-time checks. */
 
1078
        wpc8769l_power_up_and_check_if_we_woke_us_up();
 
1079
 
 
1080
        /* Configure the driver hooks. */
 
1081
        driver.features = LIRC_CAN_REC_MODE2;
 
1082
        driver.minor = lirc_register_driver(&driver);
 
1083
        if (driver.minor < 0) {
 
1084
                eprintk("lirc_register_driver failed!\n");
 
1085
                rc = -EIO;
 
1086
                goto exit_platform_exit;
 
1087
        }
 
1088
 
 
1089
        iprintk("Driver loaded.\n");
 
1090
 
 
1091
        return 0; /* Everything OK. */
 
1092
 
 
1093
exit_platform_exit:
 
1094
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
 
1095
        lirc_wpc8769l_platform_exit();
 
1096
 
 
1097
exit_release_region_2:
 
1098
#endif
 
1099
        if (baseport2)
 
1100
                release_region(baseport2, WPC8769L_IO_REGION_2_SIZE);
 
1101
 
 
1102
exit_release_region_1:
 
1103
        release_region(baseport1, WPC8769L_IO_REGION_1_SIZE);
 
1104
 
 
1105
        return rc;
 
1106
}
 
1107
 
 
1108
module_init(lirc_wpc8769l_module_init);
 
1109
 
 
1110
static void __exit lirc_wpc8769l_module_exit(void)
 
1111
{
 
1112
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
 
1113
        /* Unregister the platform driver and device. */
 
1114
        lirc_wpc8769l_platform_exit();
 
1115
#endif
 
1116
 
 
1117
        /* Unregister the LIRC driver. */
 
1118
        lirc_unregister_driver(driver.minor);
 
1119
 
 
1120
        /* Release the second range. */
 
1121
        if (baseport2)
 
1122
                release_region(baseport2, WPC8769L_IO_REGION_2_SIZE);
 
1123
 
 
1124
        /* Release the first range. */
 
1125
        release_region(baseport1, WPC8769L_IO_REGION_1_SIZE);
 
1126
 
 
1127
        iprintk("Driver unloaded.\n");
 
1128
}
 
1129
 
 
1130
module_exit(lirc_wpc8769l_module_exit);
 
1131
 
 
1132
MODULE_LICENSE("GPL");
 
1133
MODULE_AUTHOR("Juan J. Garcia de Soria");
 
1134
MODULE_DESCRIPTION("Driver for the integrated Winbond WPC8769L-based IR\
 
1135
 receiver found in Acer laptops.");
 
1136
MODULE_VERSION("0.0");
 
1137
 
 
1138
module_param(debug, bool, S_IRUGO | S_IWUSR);
 
1139
MODULE_PARM_DESC(debug, "Enable debugging messages");
 
1140
 
 
1141
module_param(baseport1, uint, S_IRUGO);
 
1142
MODULE_PARM_DESC(baseport1,
 
1143
        "First I/O range base address (default: ACPI autodetect).");
 
1144
 
 
1145
module_param(baseport2, uint, S_IRUGO);
 
1146
MODULE_PARM_DESC(baseport2,
 
1147
        "Second I/O range base address (default: ACPI autodetect).");
 
1148
 
 
1149
module_param(irq, uint, S_IRUGO);
 
1150
MODULE_PARM_DESC(irq, "IRQ number (default: ACPI autodetect).");
 
1151
 
 
1152
module_param(skip_probe, bool, S_IRUGO);
 
1153
MODULE_PARM_DESC(skip_probe,
 
1154
        "Skip ACPI-based device detection \
 
1155
(default: false for ACPI autodetect).");
 
1156
 
 
1157
#ifdef LIRC_WPC8769L_WAKEUP
 
1158
module_param(protocol_select, int, S_IRUGO);
 
1159
MODULE_PARM_DESC(protocol_select,
 
1160
        "Define the protocol for wake up functions (default: 2).");
 
1161
 
 
1162
module_param(max_info_bits, int, S_IRUGO);
 
1163
MODULE_PARM_DESC(max_info_bits,
 
1164
        "Define the maximum info bits for wake up functions (default: 24).");
 
1165
 
 
1166
module_param(rc_wakeup_code, uint, S_IRUGO);
 
1167
MODULE_PARM_DESC(rc_wakeup_code,
 
1168
        "Define the RC code value for wake up functions\
 
1169
 (default: 0x7ffffbf3).");
 
1170
 
 
1171
module_param(rc_wakeup_mask, uint, S_IRUGO);
 
1172
MODULE_PARM_DESC(rc_wakeup_mask,
 
1173
        "Define the RC code mask for wake up functions (default: 0xff000fff).");
 
1174
#endif
 
1175
 
 
1176
EXPORT_NO_SYMBOLS;
 
1177
 
 
1178
#endif /* MODULE */
 
1179