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 + -
显示快捷键?