sonypi.c
来自「linux 内核源代码」· C语言 代码 · 共 1,571 行 · 第 1/3 页
C
1,571 行
#ifdef CONFIG_ACPI_EC if (SONYPI_ACPI_ACTIVE) return ec_write(addr, value);#endif wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); outb_p(0x81, SONYPI_CST_IOPORT); wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); outb_p(addr, SONYPI_DATA_IOPORT); wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); outb_p(value, SONYPI_DATA_IOPORT); wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); return 0;}static int sonypi_ec_read(u8 addr, u8 *value){#ifdef CONFIG_ACPI_EC if (SONYPI_ACPI_ACTIVE) return ec_read(addr, value);#endif wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG); outb_p(0x80, SONYPI_CST_IOPORT); wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); outb_p(addr, SONYPI_DATA_IOPORT); wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG); *value = inb_p(SONYPI_DATA_IOPORT); return 0;}static int ec_read16(u8 addr, u16 *value){ u8 val_lb, val_hb; if (sonypi_ec_read(addr, &val_lb)) return -1; if (sonypi_ec_read(addr + 1, &val_hb)) return -1; *value = val_lb | (val_hb << 8); return 0;}/* Initializes the device - this comes from the AML code in the ACPI bios */static void sonypi_type1_srs(void){ u32 v; pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); v = (v & 0xFFFF0000) | ((u32) sonypi_device.ioport1); pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); v = (v & 0xFFF0FFFF) | (((u32) sonypi_device.ioport1 ^ sonypi_device.ioport2) << 16); pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); v = inl(SONYPI_IRQ_PORT); v &= ~(((u32) 0x3) << SONYPI_IRQ_SHIFT); v |= (((u32) sonypi_device.bits) << SONYPI_IRQ_SHIFT); outl(v, SONYPI_IRQ_PORT); pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); v = (v & 0xFF1FFFFF) | 0x00C00000; pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);}static void sonypi_type2_srs(void){ if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8)) printk(KERN_WARNING "ec_write failed\n"); if (sonypi_ec_write(SONYPI_SLOB, sonypi_device.ioport1 & 0x00FF)) printk(KERN_WARNING "ec_write failed\n"); if (sonypi_ec_write(SONYPI_SIRQ, sonypi_device.bits)) printk(KERN_WARNING "ec_write failed\n"); udelay(10);}static void sonypi_type3_srs(void){ u16 v16; u8 v8; /* This model type uses the same initialiazation of * the embedded controller as the type2 models. */ sonypi_type2_srs(); /* Initialization of PCI config space of the LPC interface bridge. */ v16 = (sonypi_device.ioport1 & 0xFFF0) | 0x01; pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, v16); pci_read_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, &v8); v8 = (v8 & 0xCF) | 0x10; pci_write_config_byte(sonypi_device.dev, SONYPI_TYPE3_MISC, v8);}/* Disables the device - this comes from the AML code in the ACPI bios */static void sonypi_type1_dis(void){ u32 v; pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v); v = v & 0xFF3FFFFF; pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v); v = inl(SONYPI_IRQ_PORT); v |= (0x3 << SONYPI_IRQ_SHIFT); outl(v, SONYPI_IRQ_PORT);}static void sonypi_type2_dis(void){ if (sonypi_ec_write(SONYPI_SHIB, 0)) printk(KERN_WARNING "ec_write failed\n"); if (sonypi_ec_write(SONYPI_SLOB, 0)) printk(KERN_WARNING "ec_write failed\n"); if (sonypi_ec_write(SONYPI_SIRQ, 0)) printk(KERN_WARNING "ec_write failed\n");}static void sonypi_type3_dis(void){ sonypi_type2_dis(); udelay(10); pci_write_config_word(sonypi_device.dev, SONYPI_TYPE3_GID2, 0);}static u8 sonypi_call1(u8 dev){ u8 v1, v2; wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(dev, sonypi_device.ioport2); v1 = inb_p(sonypi_device.ioport2); v2 = inb_p(sonypi_device.ioport1); return v2;}static u8 sonypi_call2(u8 dev, u8 fn){ u8 v1; wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(dev, sonypi_device.ioport2); wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(fn, sonypi_device.ioport1); v1 = inb_p(sonypi_device.ioport1); return v1;}static u8 sonypi_call3(u8 dev, u8 fn, u8 v){ u8 v1; wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(dev, sonypi_device.ioport2); wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(fn, sonypi_device.ioport1); wait_on_command(0, inb_p(sonypi_device.ioport2) & 2, ITERATIONS_LONG); outb(v, sonypi_device.ioport1); v1 = inb_p(sonypi_device.ioport1); return v1;}#if 0/* Get brightness, hue etc. Unreliable... */static u8 sonypi_read(u8 fn){ u8 v1, v2; int n = 100; while (n--) { v1 = sonypi_call2(0x8f, fn); v2 = sonypi_call2(0x8f, fn); if (v1 == v2 && v1 != 0xff) return v1; } return 0xff;}#endif/* Set brightness, hue etc */static void sonypi_set(u8 fn, u8 v){ wait_on_command(0, sonypi_call3(0x90, fn, v), ITERATIONS_SHORT);}/* Tests if the camera is ready */static int sonypi_camera_ready(void){ u8 v; v = sonypi_call2(0x8f, SONYPI_CAMERA_STATUS); return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));}/* Turns the camera off */static void sonypi_camera_off(void){ sonypi_set(SONYPI_CAMERA_PICTURE, SONYPI_CAMERA_MUTE_MASK); if (!sonypi_device.camera_power) return; sonypi_call2(0x91, 0); sonypi_device.camera_power = 0;}/* Turns the camera on */static void sonypi_camera_on(void){ int i, j; if (sonypi_device.camera_power) return; for (j = 5; j > 0; j--) { while (sonypi_call2(0x91, 0x1)) msleep(10); sonypi_call1(0x93); for (i = 400; i > 0; i--) { if (sonypi_camera_ready()) break; msleep(10); } if (i) break; } if (j == 0) { printk(KERN_WARNING "sonypi: failed to power on camera\n"); return; } sonypi_set(0x10, 0x5a); sonypi_device.camera_power = 1;}/* sets the bluetooth subsystem power state */static void sonypi_setbluetoothpower(u8 state){ state = !!state; if (sonypi_device.bluetooth_power == state) return; sonypi_call2(0x96, state); sonypi_call1(0x82); sonypi_device.bluetooth_power = state;}static void input_keyrelease(struct work_struct *work){ struct sonypi_keypress kp; while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp, sizeof(kp)) == sizeof(kp)) { msleep(10); input_report_key(kp.dev, kp.key, 0); input_sync(kp.dev); }}static void sonypi_report_input_event(u8 event){ struct input_dev *jog_dev = sonypi_device.input_jog_dev; struct input_dev *key_dev = sonypi_device.input_key_dev; struct sonypi_keypress kp = { NULL }; int i; switch (event) { case SONYPI_EVENT_JOGDIAL_UP: case SONYPI_EVENT_JOGDIAL_UP_PRESSED: input_report_rel(jog_dev, REL_WHEEL, 1); input_sync(jog_dev); break; case SONYPI_EVENT_JOGDIAL_DOWN: case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED: input_report_rel(jog_dev, REL_WHEEL, -1); input_sync(jog_dev); break; case SONYPI_EVENT_JOGDIAL_PRESSED: kp.key = BTN_MIDDLE; kp.dev = jog_dev; break; case SONYPI_EVENT_FNKEY_RELEASED: /* Nothing, not all VAIOs generate this event */ break; default: for (i = 0; sonypi_inputkeys[i].sonypiev; i++) if (event == sonypi_inputkeys[i].sonypiev) { kp.dev = key_dev; kp.key = sonypi_inputkeys[i].inputev; break; } break; } if (kp.dev) { input_report_key(kp.dev, kp.key, 1); input_sync(kp.dev); kfifo_put(sonypi_device.input_fifo, (unsigned char *)&kp, sizeof(kp)); schedule_work(&sonypi_device.input_work); }}/* Interrupt handler: some event is available */static irqreturn_t sonypi_irq(int irq, void *dev_id){ u8 v1, v2, event = 0; int i, j; v1 = inb_p(sonypi_device.ioport1); v2 = inb_p(sonypi_device.ioport1 + sonypi_device.evtype_offset); for (i = 0; sonypi_eventtypes[i].model; i++) { if (sonypi_device.model != sonypi_eventtypes[i].model) continue; if ((v2 & sonypi_eventtypes[i].data) != sonypi_eventtypes[i].data) continue; if (!(mask & sonypi_eventtypes[i].mask)) continue; for (j = 0; sonypi_eventtypes[i].events[j].event; j++) { if (v1 == sonypi_eventtypes[i].events[j].data) { event = sonypi_eventtypes[i].events[j].event; goto found; } } } if (verbose) printk(KERN_WARNING "sonypi: unknown event port1=0x%02x,port2=0x%02x\n", v1, v2); /* We need to return IRQ_HANDLED here because there *are* * events belonging to the sonypi device we don't know about, * but we still don't want those to pollute the logs... */ return IRQ_HANDLED;found: if (verbose > 1) printk(KERN_INFO "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2); if (useinput) sonypi_report_input_event(event);#ifdef CONFIG_ACPI if (sonypi_acpi_device) acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);#endif kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event)); kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN); wake_up_interruptible(&sonypi_device.fifo_proc_list); return IRQ_HANDLED;}static int sonypi_misc_fasync(int fd, struct file *filp, int on){ int retval; retval = fasync_helper(fd, filp, on, &sonypi_device.fifo_async); if (retval < 0) return retval; return 0;}static int sonypi_misc_release(struct inode *inode, struct file *file){ sonypi_misc_fasync(-1, file, 0); mutex_lock(&sonypi_device.lock); sonypi_device.open_count--; mutex_unlock(&sonypi_device.lock); return 0;}static int sonypi_misc_open(struct inode *inode, struct file *file){ mutex_lock(&sonypi_device.lock); /* Flush input queue on first open */ if (!sonypi_device.open_count) kfifo_reset(sonypi_device.fifo); sonypi_device.open_count++; mutex_unlock(&sonypi_device.lock); return 0;}static ssize_t sonypi_misc_read(struct file *file, char __user *buf, size_t count, loff_t *pos){ ssize_t ret; unsigned char c; if ((kfifo_len(sonypi_device.fifo) == 0) && (file->f_flags & O_NONBLOCK)) return -EAGAIN; ret = wait_event_interruptible(sonypi_device.fifo_proc_list, kfifo_len(sonypi_device.fifo) != 0); if (ret) return ret; while (ret < count && (kfifo_get(sonypi_device.fifo, &c, sizeof(c)) == sizeof(c))) { if (put_user(c, buf++)) return -EFAULT; ret++; } if (ret > 0) { struct inode *inode = file->f_path.dentry->d_inode; inode->i_atime = current_fs_time(inode->i_sb); } return ret;}static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait){ poll_wait(file, &sonypi_device.fifo_proc_list, wait); if (kfifo_len(sonypi_device.fifo)) return POLLIN | POLLRDNORM; return 0;}static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg){ int ret = 0; void __user *argp = (void __user *)arg; u8 val8; u16 val16; mutex_lock(&sonypi_device.lock); switch (cmd) { case SONYPI_IOCGBRT: if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) { ret = -EIO; break; } if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCSBRT: if (copy_from_user(&val8, argp, sizeof(val8))) { ret = -EFAULT; break; } if (sonypi_ec_write(SONYPI_LCD_LIGHT, val8)) ret = -EIO; break; case SONYPI_IOCGBAT1CAP: if (ec_read16(SONYPI_BAT1_FULL, &val16)) { ret = -EIO; break; } if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT1REM: if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { ret = -EIO; break; } if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT2CAP: if (ec_read16(SONYPI_BAT2_FULL, &val16)) { ret = -EIO; break; } if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBAT2REM: if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { ret = -EIO; break; } if (copy_to_user(argp, &val16, sizeof(val16))) ret = -EFAULT; break; case SONYPI_IOCGBATFLAGS: if (sonypi_ec_read(SONYPI_BAT_FLAGS, &val8)) { ret = -EIO; break; } val8 &= 0x07; if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCGBLUE: val8 = sonypi_device.bluetooth_power; if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCSBLUE: if (copy_from_user(&val8, argp, sizeof(val8))) { ret = -EFAULT; break; } sonypi_setbluetoothpower(val8); break; /* FAN Controls */ case SONYPI_IOCGFAN: if (sonypi_ec_read(SONYPI_FAN0_STATUS, &val8)) { ret = -EIO; break; } if (copy_to_user(argp, &val8, sizeof(val8))) ret = -EFAULT; break; case SONYPI_IOCSFAN: if (copy_from_user(&val8, argp, sizeof(val8))) { ret = -EFAULT; break; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?