linux-old/drivers/char/sonypi.c
<<
>>
Prefs
   1/*
   2 * Sony Programmable I/O Control Device driver for VAIO
   3 *
   4 * Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
   5 *
   6 * Copyright (C) 2001-2002 AlcĂ´ve <www.alcove.com>
   7 *
   8 * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
   9 *
  10 * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
  11 *
  12 * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
  13 *
  14 * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
  15 *
  16 * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
  17 *
  18 * This program is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation; either version 2 of the License, or
  21 * (at your option) any later version.
  22 * 
  23 * This program is distributed in the hope that it will be useful,
  24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26 * GNU General Public License for more details.
  27 * 
  28 * You should have received a copy of the GNU General Public License
  29 * along with this program; if not, write to the Free Software
  30 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  31 *
  32 */
  33
  34#include <linux/config.h>
  35#include <linux/module.h>
  36#include <linux/input.h>
  37#include <linux/pci.h>
  38#include <linux/sched.h>
  39#include <linux/init.h>
  40#include <linux/interrupt.h>
  41#include <linux/miscdevice.h>
  42#include <linux/poll.h>
  43#include <linux/delay.h>
  44#include <linux/wait.h>
  45#include <linux/acpi.h>
  46
  47#include <asm/uaccess.h>
  48#include <asm/io.h>
  49#include <asm/system.h>
  50
  51#include "sonypi.h"
  52#include <linux/sonypi.h>
  53
  54static struct sonypi_device sonypi_device;
  55static int minor = -1;
  56static int verbose; /* = 0 */
  57static int fnkeyinit; /* = 0 */
  58static int camera; /* = 0 */
  59static int compat; /* = 0 */
  60static int useinput = 1;
  61static unsigned long mask = 0xffffffff;
  62
  63/* Inits the queue */
  64static inline void sonypi_initq(void) {
  65        sonypi_device.queue.head = sonypi_device.queue.tail = 0;
  66        sonypi_device.queue.len = 0;
  67        sonypi_device.queue.s_lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
  68        init_waitqueue_head(&sonypi_device.queue.proc_list);
  69}
  70
  71/* Pulls an event from the queue */
  72static inline unsigned char sonypi_pullq(void) {
  73        unsigned char result;
  74        unsigned long flags;
  75
  76        spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
  77        if (!sonypi_device.queue.len) {
  78                spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  79                return 0;
  80        }
  81        result = sonypi_device.queue.buf[sonypi_device.queue.head];
  82        sonypi_device.queue.head++;
  83        sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
  84        sonypi_device.queue.len--;
  85        spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
  86        return result;
  87}
  88
  89/* Pushes an event into the queue */
  90static inline void sonypi_pushq(unsigned char event) {
  91        unsigned long flags;
  92
  93        spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
  94        if (sonypi_device.queue.len == SONYPI_BUF_SIZE) {
  95                /* remove the first element */
  96                sonypi_device.queue.head++;
  97                sonypi_device.queue.head &= (SONYPI_BUF_SIZE - 1);
  98                sonypi_device.queue.len--;
  99        }
 100        sonypi_device.queue.buf[sonypi_device.queue.tail] = event;
 101        sonypi_device.queue.tail++;
 102        sonypi_device.queue.tail &= (SONYPI_BUF_SIZE - 1);
 103        sonypi_device.queue.len++;
 104
 105        kill_fasync(&sonypi_device.queue.fasync, SIGIO, POLL_IN);
 106        wake_up_interruptible(&sonypi_device.queue.proc_list);
 107        spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
 108}
 109
 110/* Tests if the queue is empty */
 111static inline int sonypi_emptyq(void) {
 112        int result;
 113        unsigned long flags;
 114
 115        spin_lock_irqsave(&sonypi_device.queue.s_lock, flags);
 116        result = (sonypi_device.queue.len == 0);
 117        spin_unlock_irqrestore(&sonypi_device.queue.s_lock, flags);
 118        return result;
 119}
 120
 121static int ec_read16(u8 addr, u16 *value) {
 122        u8 val_lb, val_hb;
 123        if (sonypi_ec_read(addr, &val_lb))
 124                return -1;
 125        if (sonypi_ec_read(addr + 1, &val_hb))
 126                return -1;
 127        *value = val_lb | (val_hb << 8);
 128        return 0;
 129}
 130
 131/* Initializes the device - this comes from the AML code in the ACPI bios */
 132static void sonypi_type1_srs(void) {
 133        u32 v;
 134
 135        pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
 136        v = (v & 0xFFFF0000) | ((u32)sonypi_device.ioport1);
 137        pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 138
 139        pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
 140        v = (v & 0xFFF0FFFF) | 
 141            (((u32)sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16);
 142        pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 143
 144        v = inl(SONYPI_IRQ_PORT);
 145        v &= ~(((u32)0x3) << SONYPI_IRQ_SHIFT);
 146        v |= (((u32)sonypi_device.bits) << SONYPI_IRQ_SHIFT);
 147        outl(v, SONYPI_IRQ_PORT);
 148
 149        pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
 150        v = (v & 0xFF1FFFFF) | 0x00C00000;
 151        pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 152}
 153
 154static void sonypi_type2_srs(void) {
 155        if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
 156                printk(KERN_WARNING "ec_write failed\n");
 157        if (sonypi_ec_write(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF))
 158                printk(KERN_WARNING "ec_write failed\n");
 159        if (sonypi_ec_write(SONYPI_SIRQ,  sonypi_device.bits))
 160                printk(KERN_WARNING "ec_write failed\n");
 161        udelay(10);
 162}
 163
 164/* Disables the device - this comes from the AML code in the ACPI bios */
 165static void sonypi_type1_dis(void) {
 166        u32 v;
 167
 168        pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
 169        v = v & 0xFF3FFFFF;
 170        pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 171
 172        v = inl(SONYPI_IRQ_PORT);
 173        v |= (0x3 << SONYPI_IRQ_SHIFT);
 174        outl(v, SONYPI_IRQ_PORT);
 175}
 176
 177static void sonypi_type2_dis(void) {
 178        if (sonypi_ec_write(SONYPI_SHIB, 0))
 179                printk(KERN_WARNING "ec_write failed\n");
 180        if (sonypi_ec_write(SONYPI_SLOB, 0))
 181                printk(KERN_WARNING "ec_write failed\n");
 182        if (sonypi_ec_write(SONYPI_SIRQ, 0))
 183                printk(KERN_WARNING "ec_write failed\n");
 184}
 185
 186static u8 sonypi_call1(u8 dev) {
 187        u8 v1, v2;
 188
 189        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 190        outb(dev, sonypi_device.ioport2);
 191        v1 = inb_p(sonypi_device.ioport2);
 192        v2 = inb_p(sonypi_device.ioport1);
 193        return v2;
 194}
 195
 196static u8 sonypi_call2(u8 dev, u8 fn) {
 197        u8 v1;
 198
 199        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 200        outb(dev, sonypi_device.ioport2);
 201        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 202        outb(fn, sonypi_device.ioport1);
 203        v1 = inb_p(sonypi_device.ioport1);
 204        return v1;
 205}
 206
 207static u8 sonypi_call3(u8 dev, u8 fn, u8 v) {
 208        u8 v1;
 209
 210        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 211        outb(dev, sonypi_device.ioport2);
 212        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 213        outb(fn, sonypi_device.ioport1);
 214        wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG);
 215        outb(v, sonypi_device.ioport1);
 216        v1 = inb_p(sonypi_device.ioport1);
 217        return v1;
 218}
 219
 220static u8 sonypi_read(u8 fn) {
 221        u8 v1, v2;
 222        int n = 100;
 223
 224        while (n--) {
 225                v1 = sonypi_call2(0x8f, fn);
 226                v2 = sonypi_call2(0x8f, fn);
 227                if (v1 == v2 && v1 != 0xff)
 228                        return v1;
 229        }
 230        return 0xff;
 231}
 232
 233/* Set brightness, hue etc */
 234static void sonypi_set(u8 fn, u8 v) {
 235        
 236        wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);
 237}
 238
 239/* Tests if the camera is ready */
 240static int sonypi_camera_ready(void) {
 241        u8 v;
 242
 243        v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS);
 244        return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
 245}
 246
 247/* Turns the camera off */
 248static void sonypi_camera_off(void) {
 249
 250        sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK);
 251
 252        if (!sonypi_device.camera_power)
 253                return;
 254
 255        sonypi_call2(0x91, 0); 
 256        sonypi_device.camera_power = 0;
 257}
 258
 259/* Turns the camera on */
 260static void sonypi_camera_on(void) {
 261        int i, j;
 262
 263        if (sonypi_device.camera_power)
 264                return;
 265
 266        for (j = 5; j > 0; j--) {
 267
 268                while (sonypi_call2(0x91, 0x1)) {
 269                        set_current_state(TASK_UNINTERRUPTIBLE);
 270                        schedule_timeout(1);
 271                }
 272                sonypi_call1(0x93);
 273
 274                for (i = 400; i > 0; i--) {
 275                        if (sonypi_camera_ready())
 276                                break;
 277                        set_current_state(TASK_UNINTERRUPTIBLE);
 278                        schedule_timeout(1);
 279                }
 280                if (i)
 281                        break;
 282        }
 283        
 284        if (j == 0) {
 285                printk(KERN_WARNING "sonypi: failed to power on camera\n");
 286                return;
 287        }
 288
 289        sonypi_set(0x10, 0x5a);
 290        sonypi_device.camera_power = 1;
 291}
 292
 293/* sets the bluetooth subsystem power state */
 294static void sonypi_setbluetoothpower(u8 state) {
 295
 296        state = !!state;
 297        if (sonypi_device.bluetooth_power == state) 
 298                return;
 299        
 300        sonypi_call2(0x96, state);
 301        sonypi_call1(0x82);
 302        sonypi_device.bluetooth_power = state;
 303}
 304
 305/* Interrupt handler: some event is available */
 306static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
 307        u8 v1, v2, event = 0;
 308        int i, j;
 309
 310        v1 = inb_p(sonypi_device.ioport1);
 311        v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset);
 312
 313        for (i = 0; sonypi_eventtypes[i].model; i++) {
 314                if (sonypi_device.model != sonypi_eventtypes[i].model)
 315                        continue;
 316                if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data)
 317                        continue;
 318                if (! (mask & sonypi_eventtypes[i].mask))
 319                        continue;
 320                for (j = 0; sonypi_eventtypes[i].events[j].event; j++) {
 321                        if (v1 == sonypi_eventtypes[i].events[j].data) {
 322                                event = sonypi_eventtypes[i].events[j].event;
 323                                goto found;
 324                        }
 325                }
 326        }
 327
 328        if (verbose)
 329                printk(KERN_WARNING 
 330                       "sonypi: unknown event port1=0x%02x,port2=0x%02x\n",v1,v2);
 331        /* We need to return IRQ_HANDLED here because there *are*
 332         * events belonging to the sonypi device we don't know about, 
 333         * but we still don't want those to pollute the logs... */
 334        return IRQ_HANDLED;
 335
 336found:
 337        if (verbose > 1)
 338                printk(KERN_INFO 
 339                       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
 340
 341#ifdef SONYPI_USE_INPUT
 342        if (useinput) {
 343                struct input_dev *jog_dev = &sonypi_device.jog_dev;
 344                if (event == SONYPI_EVENT_JOGDIAL_PRESSED)
 345                        input_report_key(jog_dev, BTN_MIDDLE, 1);
 346                else if (event == SONYPI_EVENT_ANYBUTTON_RELEASED)
 347                        input_report_key(jog_dev, BTN_MIDDLE, 0);
 348                else if ((event == SONYPI_EVENT_JOGDIAL_UP) ||
 349                         (event == SONYPI_EVENT_JOGDIAL_UP_PRESSED))
 350                        input_report_rel(jog_dev, REL_WHEEL, 1);
 351                else if ((event == SONYPI_EVENT_JOGDIAL_DOWN) ||
 352                         (event == SONYPI_EVENT_JOGDIAL_DOWN_PRESSED))
 353                        input_report_rel(jog_dev, REL_WHEEL, -1);
 354        }
 355#endif /* SONYPI_USE_INPUT */
 356        sonypi_pushq(event);
 357        return IRQ_HANDLED;
 358}
 359
 360/* External camera command (exported to the motion eye v4l driver) */
 361u8 sonypi_camera_command(int command, u8 value) {
 362        u8 ret = 0;
 363
 364        if (!camera)
 365                return 0;
 366
 367        down(&sonypi_device.lock);
 368
 369        switch(command) {
 370                case SONYPI_COMMAND_GETCAMERA:
 371                        ret = sonypi_camera_ready();
 372                        break;
 373                case SONYPI_COMMAND_SETCAMERA:
 374                        if (value)
 375                                sonypi_camera_on();
 376                        else
 377                                sonypi_camera_off();
 378                        break;
 379                case SONYPI_COMMAND_GETCAMERABRIGHTNESS:
 380                        ret = sonypi_read(SONYPI_CAMERA_BRIGHTNESS);
 381                        break;
 382                case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
 383                        sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
 384                        break;
 385                case SONYPI_COMMAND_GETCAMERACONTRAST:
 386                        ret = sonypi_read(SONYPI_CAMERA_CONTRAST);
 387                        break;
 388                case SONYPI_COMMAND_SETCAMERACONTRAST:
 389                        sonypi_set(SONYPI_CAMERA_CONTRAST, value);
 390                        break;
 391                case SONYPI_COMMAND_GETCAMERAHUE:
 392                        ret = sonypi_read(SONYPI_CAMERA_HUE);
 393                        break;
 394                case SONYPI_COMMAND_SETCAMERAHUE:
 395                        sonypi_set(SONYPI_CAMERA_HUE, value);
 396                        break;
 397                case SONYPI_COMMAND_GETCAMERACOLOR:
 398                        ret = sonypi_read(SONYPI_CAMERA_COLOR);
 399                        break;
 400                case SONYPI_COMMAND_SETCAMERACOLOR:
 401                        sonypi_set(SONYPI_CAMERA_COLOR, value);
 402                        break;
 403                case SONYPI_COMMAND_GETCAMERASHARPNESS:
 404                        ret = sonypi_read(SONYPI_CAMERA_SHARPNESS);
 405                        break;
 406                case SONYPI_COMMAND_SETCAMERASHARPNESS:
 407                        sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
 408                        break;
 409                case SONYPI_COMMAND_GETCAMERAPICTURE:
 410                        ret = sonypi_read(SONYPI_CAMERA_PICTURE);
 411                        break;
 412                case SONYPI_COMMAND_SETCAMERAPICTURE:
 413                        sonypi_set(SONYPI_CAMERA_PICTURE, value);
 414                        break;
 415                case SONYPI_COMMAND_GETCAMERAAGC:
 416                        ret = sonypi_read(SONYPI_CAMERA_AGC);
 417                        break;
 418                case SONYPI_COMMAND_SETCAMERAAGC:
 419                        sonypi_set(SONYPI_CAMERA_AGC, value);
 420                        break;
 421                case SONYPI_COMMAND_GETCAMERADIRECTION:
 422                        ret = sonypi_read(SONYPI_CAMERA_STATUS);
 423                        ret &= SONYPI_DIRECTION_BACKWARDS;
 424                        break;
 425                case SONYPI_COMMAND_GETCAMERAROMVERSION:
 426                        ret = sonypi_read(SONYPI_CAMERA_ROMVERSION);
 427                        break;
 428                case SONYPI_COMMAND_GETCAMERAREVISION:
 429                        ret = sonypi_read(SONYPI_CAMERA_REVISION);
 430                        break;
 431        }
 432        up(&sonypi_device.lock);
 433        return ret;
 434}
 435
 436static int sonypi_misc_fasync(int fd, struct file *filp, int on) {
 437        int retval;
 438
 439        retval = fasync_helper(fd, filp, on, &sonypi_device.queue.fasync);
 440        if (retval < 0)
 441                return retval;
 442        return 0;
 443}
 444
 445static int sonypi_misc_release(struct inode * inode, struct file * file) {
 446        sonypi_misc_fasync(-1, file, 0);
 447        down(&sonypi_device.lock);
 448        sonypi_device.open_count--;
 449        up(&sonypi_device.lock);
 450        return 0;
 451}
 452
 453static int sonypi_misc_open(struct inode * inode, struct file * file) {
 454        down(&sonypi_device.lock);
 455        /* Flush input queue on first open */
 456        if (!sonypi_device.open_count)
 457                sonypi_initq();
 458        sonypi_device.open_count++;
 459        up(&sonypi_device.lock);
 460        return 0;
 461}
 462
 463static ssize_t sonypi_misc_read(struct file * file, char * buf, 
 464                                size_t count, loff_t *pos) {
 465        DECLARE_WAITQUEUE(wait, current);
 466        ssize_t i = count;
 467        unsigned char c;
 468
 469        if (sonypi_emptyq()) {
 470                if (file->f_flags & O_NONBLOCK)
 471                        return -EAGAIN;
 472                add_wait_queue(&sonypi_device.queue.proc_list, &wait);
 473repeat:
 474                set_current_state(TASK_INTERRUPTIBLE);
 475                if (sonypi_emptyq() && !signal_pending(current)) {
 476                        schedule();
 477                        goto repeat;
 478                }
 479                current->state = TASK_RUNNING;
 480                remove_wait_queue(&sonypi_device.queue.proc_list, &wait);
 481        }
 482        while (i > 0 && !sonypi_emptyq()) {
 483                c = sonypi_pullq();
 484                put_user(c, buf++);
 485                i--;
 486        }
 487        if (count - i) {
 488                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
 489                return count-i;
 490        }
 491        if (signal_pending(current))
 492                return -ERESTARTSYS;
 493        return 0;
 494}
 495
 496static unsigned int sonypi_misc_poll(struct file *file, poll_table * wait) {
 497        poll_wait(file, &sonypi_device.queue.proc_list, wait);
 498        if (!sonypi_emptyq())
 499                return POLLIN | POLLRDNORM;
 500        return 0;
 501}
 502
 503static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, 
 504                             unsigned int cmd, unsigned long arg) {
 505        int ret = 0;
 506        u8 val8;
 507        u16 val16;
 508
 509        down(&sonypi_device.lock);
 510        switch (cmd) {
 511        case SONYPI_IOCGBRT:
 512                if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
 513                        ret = -EIO;
 514                        break;
 515                }
 516                if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 517                        ret = -EFAULT;
 518                break;
 519        case SONYPI_IOCSBRT:
 520                if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 521                        ret = -EFAULT;
 522                        break;
 523                }
 524                if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8))
 525                        ret = -EIO;
 526                break;
 527        case SONYPI_IOCGBAT1CAP:
 528                if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
 529                        ret = -EIO;
 530                        break;
 531                }
 532                if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
 533                        ret = -EFAULT;
 534                break;
 535        case SONYPI_IOCGBAT1REM:
 536                if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
 537                        ret = -EIO;
 538                        break;
 539                }
 540                if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
 541                        ret = -EFAULT;
 542                break;
 543        case SONYPI_IOCGBAT2CAP:
 544                if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
 545                        ret = -EIO;
 546                        break;
 547                }
 548                if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
 549                        ret = -EFAULT;
 550                break;
 551        case SONYPI_IOCGBAT2REM:
 552                if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
 553                        ret = -EIO;
 554                        break;
 555                }
 556                if (copy_to_user((u16 *)arg, &val16, sizeof(val16)))
 557                        ret = -EFAULT;
 558                break;
 559        case SONYPI_IOCGBATFLAGS:
 560                if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) {
 561                        ret = -EIO;
 562                        break;
 563                }
 564                val8 &= 0x07;
 565                if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 566                        ret = -EFAULT;
 567                break;
 568        case SONYPI_IOCGBLUE:
 569                val8 = sonypi_device.bluetooth_power;
 570                if (copy_to_user((u8 *)arg, &val8, sizeof(val8)))
 571                        ret = -EFAULT;
 572                break;
 573        case SONYPI_IOCSBLUE:
 574                if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
 575                        ret = -EFAULT;
 576                        break;
 577                }
 578                sonypi_setbluetoothpower(val8);
 579                break;
 580        default:
 581                ret = -EINVAL;
 582        }
 583        up(&sonypi_device.lock);
 584        return ret;
 585}
 586
 587static struct file_operations sonypi_misc_fops = {
 588        .owner          = THIS_MODULE,
 589        .read           = sonypi_misc_read,
 590        .poll           = sonypi_misc_poll,
 591        .open           = sonypi_misc_open,
 592        .release        = sonypi_misc_release,
 593        .fasync         = sonypi_misc_fasync,
 594        .ioctl          = sonypi_misc_ioctl,
 595};
 596
 597struct miscdevice sonypi_misc_device = {
 598        -1, "sonypi", &sonypi_misc_fops
 599};
 600
 601#ifdef CONFIG_PM
 602static int sonypi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) {
 603        static int old_camera_power;
 604
 605        switch (rqst) {
 606        case PM_SUSPEND:
 607                sonypi_call2(0x81, 0); /* make sure we don't get any more events */
 608                if (camera) {
 609                        old_camera_power = sonypi_device.camera_power;
 610                        sonypi_camera_off();
 611                }
 612                if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 613                        sonypi_type2_dis();
 614                else
 615                        sonypi_type1_dis();
 616                /* disable ACPI mode */
 617                if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
 618                        outb(0xf1, 0xb2);
 619                break;
 620        case PM_RESUME:
 621                /* Enable ACPI mode to get Fn key events */
 622                if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
 623                        outb(0xf0, 0xb2);
 624                if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 625                        sonypi_type2_srs();
 626                else
 627                        sonypi_type1_srs();
 628                sonypi_call1(0x82);
 629                sonypi_call2(0x81, 0xff);
 630                if (compat)
 631                        sonypi_call1(0x92); 
 632                else
 633                        sonypi_call1(0x82);
 634                if (camera && old_camera_power)
 635                        sonypi_camera_on();
 636                break;
 637        }
 638        return 0;
 639}
 640#endif
 641
 642static int __devinit sonypi_probe(struct pci_dev *pcidev) {
 643        int i, ret;
 644        struct sonypi_ioport_list *ioport_list;
 645        struct sonypi_irq_list *irq_list;
 646
 647        sonypi_device.dev = pcidev;
 648        if (pcidev)
 649                sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE1;
 650        else
 651                sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
 652        sonypi_initq();
 653        init_MUTEX(&sonypi_device.lock);
 654        sonypi_device.bluetooth_power = 0;
 655        
 656        if (pcidev && pci_enable_device(pcidev)) {
 657                printk(KERN_ERR "sonypi: pci_enable_device failed\n");
 658                ret = -EIO;
 659                goto out1;
 660        }
 661
 662        sonypi_misc_device.minor = (minor == -1) ? 
 663                MISC_DYNAMIC_MINOR : minor;
 664        if ((ret = misc_register(&sonypi_misc_device))) {
 665                printk(KERN_ERR "sonypi: misc_register failed\n");
 666                goto out1;
 667        }
 668
 669        if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
 670                ioport_list = sonypi_type2_ioport_list;
 671                sonypi_device.region_size = SONYPI_TYPE2_REGION_SIZE;
 672                sonypi_device.evtype_offset = SONYPI_TYPE2_EVTYPE_OFFSET;
 673                irq_list = sonypi_type2_irq_list;
 674        }
 675        else {
 676                ioport_list = sonypi_type1_ioport_list;
 677                sonypi_device.region_size = SONYPI_TYPE1_REGION_SIZE;
 678                sonypi_device.evtype_offset = SONYPI_TYPE1_EVTYPE_OFFSET;
 679                irq_list = sonypi_type1_irq_list;
 680        }
 681
 682        for (i = 0; ioport_list[i].port1; i++) {
 683                if (request_region(ioport_list[i].port1, 
 684                                   sonypi_device.region_size, 
 685                                   "Sony Programable I/O Device")) {
 686                        /* get the ioport */
 687                        sonypi_device.ioport1 = ioport_list[i].port1;
 688                        sonypi_device.ioport2 = ioport_list[i].port2;
 689                        break;
 690                }
 691        }
 692        if (!sonypi_device.ioport1) {
 693                printk(KERN_ERR "sonypi: request_region failed\n");
 694                ret = -ENODEV;
 695                goto out2;
 696        }
 697
 698        for (i = 0; irq_list[i].irq; i++) {
 699
 700                sonypi_device.irq = irq_list[i].irq;
 701                sonypi_device.bits = irq_list[i].bits;
 702
 703                /* Enable sonypi IRQ settings */
 704                if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 705                        sonypi_type2_srs();
 706                else
 707                        sonypi_type1_srs();
 708
 709                sonypi_call1(0x82);
 710                sonypi_call2(0x81, 0xff);
 711                if (compat)
 712                        sonypi_call1(0x92); 
 713                else
 714                        sonypi_call1(0x82);
 715
 716                /* Now try requesting the irq from the system */
 717                if (!request_irq(sonypi_device.irq, sonypi_irq, 
 718                                 SA_SHIRQ, "sonypi", sonypi_irq))
 719                        break;
 720
 721                /* If request_irq failed, disable sonypi IRQ settings */
 722                if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 723                        sonypi_type2_dis();
 724                else
 725                        sonypi_type1_dis();
 726        }
 727
 728        if (!irq_list[i].irq) {
 729                printk(KERN_ERR "sonypi: request_irq failed\n");
 730                ret = -ENODEV;
 731                goto out3;
 732        }
 733
 734        /* Enable ACPI mode to get Fn key events */
 735        if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
 736                outb(0xf0, 0xb2);
 737
 738        printk(KERN_INFO "sonypi: Sony Programmable I/O Controller Driver v%d.%d.\n",
 739               SONYPI_DRIVER_MAJORVERSION,
 740               SONYPI_DRIVER_MINORVERSION);
 741        printk(KERN_INFO "sonypi: detected %s model, "
 742               "verbose = %d, fnkeyinit = %s, camera = %s, "
 743               "compat = %s, mask = 0x%08lx, useinput = %s\n",
 744               (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE1) ?
 745                        "type1" : "type2",
 746               verbose,
 747               fnkeyinit ? "on" : "off",
 748               camera ? "on" : "off",
 749               compat ? "on" : "off",
 750               mask,
 751               useinput ? "on" : "off");
 752        printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
 753               sonypi_device.irq, 
 754               sonypi_device.ioport1, sonypi_device.ioport2);
 755        if (minor == -1)
 756                printk(KERN_INFO "sonypi: device allocated minor is %d\n",
 757                       sonypi_misc_device.minor);
 758
 759#ifdef SONYPI_USE_INPUT
 760        if (useinput) {
 761                /* Initialize the Input Drivers: */
 762                sonypi_device.jog_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 763                sonypi_device.jog_dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
 764                sonypi_device.jog_dev.relbit[0] = BIT(REL_WHEEL);
 765                sonypi_device.jog_dev.name = (char *) kmalloc(
 766                        sizeof(SONYPI_INPUTNAME), GFP_KERNEL);
 767                sprintf(sonypi_device.jog_dev.name, SONYPI_INPUTNAME);
 768                sonypi_device.jog_dev.idbus = BUS_ISA;
 769                sonypi_device.jog_dev.idvendor = PCI_VENDOR_ID_SONY;
 770          
 771                input_register_device(&sonypi_device.jog_dev);
 772                printk(KERN_INFO "%s installed at input event device #%d.\n", 
 773                        sonypi_device.jog_dev.name,
 774                        sonypi_device.jog_dev.number);
 775        }
 776#endif /* SONYPI_USE_INPUT */
 777
 778#ifdef CONFIG_PM
 779        sonypi_device.pm = pm_register(PM_PCI_DEV, 0, sonypi_pm_callback);
 780#endif
 781
 782        return 0;
 783
 784out3:
 785        release_region(sonypi_device.ioport1, sonypi_device.region_size);
 786out2:
 787        misc_deregister(&sonypi_misc_device);
 788out1:
 789        return ret;
 790}
 791
 792static void __devexit sonypi_remove(void) {
 793
 794#ifdef CONFIG_PM
 795        pm_unregister(sonypi_device.pm);
 796#endif
 797
 798        sonypi_call2(0x81, 0); /* make sure we don't get any more events */
 799        
 800#ifdef SONYPI_USE_INPUT
 801        if (useinput) {
 802                input_unregister_device(&sonypi_device.jog_dev);
 803                kfree(sonypi_device.jog_dev.name);
 804        }
 805#endif /* SONYPI_USE_INPUT */
 806
 807        if (camera)
 808                sonypi_camera_off();
 809        if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2)
 810                sonypi_type2_dis();
 811        else
 812                sonypi_type1_dis();
 813        /* disable ACPI mode */
 814        if (!SONYPI_ACPI_ACTIVE && fnkeyinit)
 815                outb(0xf1, 0xb2);
 816        free_irq(sonypi_device.irq, sonypi_irq);
 817        release_region(sonypi_device.ioport1, sonypi_device.region_size);
 818        misc_deregister(&sonypi_misc_device);
 819        printk(KERN_INFO "sonypi: removed.\n");
 820}
 821
 822static int __init sonypi_init_module(void) {
 823        struct pci_dev *pcidev = NULL;
 824
 825        if (is_sony_vaio_laptop) {
 826                pcidev = pci_find_device(PCI_VENDOR_ID_INTEL, 
 827                                         PCI_DEVICE_ID_INTEL_82371AB_3, 
 828                                         NULL);
 829                return sonypi_probe(pcidev);
 830        }
 831        else
 832                return -ENODEV;
 833}
 834
 835static void __exit sonypi_cleanup_module(void) {
 836        sonypi_remove();
 837}
 838
 839#ifndef MODULE
 840static int __init sonypi_setup(char *str)  {
 841        int ints[8];
 842
 843        str = get_options(str, ARRAY_SIZE(ints), ints);
 844        if (ints[0] <= 0) 
 845                goto out;
 846        minor = ints[1];
 847        if (ints[0] == 1)
 848                goto out;
 849        verbose = ints[2];
 850        if (ints[0] == 2)
 851                goto out;
 852        fnkeyinit = ints[3];
 853        if (ints[0] == 3)
 854                goto out;
 855        camera = ints[4];
 856        if (ints[0] == 4)
 857                goto out;
 858        compat = ints[5];
 859        if (ints[0] == 5)
 860                goto out;
 861        mask = ints[6];
 862        if (ints[0] == 6)
 863                goto out;
 864        useinput = ints[7];
 865out:
 866        return 1;
 867}
 868
 869__setup("sonypi=", sonypi_setup);
 870#endif /* !MODULE */
 871        
 872/* Module entry points */
 873module_init(sonypi_init_module);
 874module_exit(sonypi_cleanup_module);
 875
 876MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
 877MODULE_DESCRIPTION("Sony Programmable I/O Control Device driver");
 878MODULE_LICENSE("GPL");
 879
 880
 881MODULE_PARM(minor,"i");
 882MODULE_PARM_DESC(minor, "minor number of the misc device, default is -1 (automatic)");
 883MODULE_PARM(verbose,"i");
 884MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
 885MODULE_PARM(fnkeyinit,"i");
 886MODULE_PARM_DESC(fnkeyinit, "set this if your Fn keys do not generate any event");
 887MODULE_PARM(camera,"i");
 888MODULE_PARM_DESC(camera, "set this if you have a MotionEye camera (PictureBook series)");
 889MODULE_PARM(compat,"i");
 890MODULE_PARM_DESC(compat, "set this if you want to enable backward compatibility mode");
 891MODULE_PARM(mask, "i");
 892MODULE_PARM_DESC(mask, "set this to the mask of event you want to enable (see doc)");
 893MODULE_PARM(useinput, "i");
 894MODULE_PARM_DESC(useinput, "if you have a jogdial, set this if you would like it to use the modern Linux Input Driver system");
 895
 896EXPORT_SYMBOL(sonypi_camera_command);
 897
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.