⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sony-laptop.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * ACPI Sony Notebook Control Driver (SNC and SPIC) * * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> * * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c * which are copyrighted by their respective authors. * * The SNY6001 driver part is based on the sonypi driver which includes * material from: * * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net> * * Copyright (C) 2005 Narayanan R S <nars@kadamba.org> * * Copyright (C) 2001-2002 Alcôve <www.alcove.com> * * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au> * * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp> * * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp> * * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com> * * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/types.h>#include <linux/backlight.h>#include <linux/platform_device.h>#include <linux/err.h>#include <linux/dmi.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/input.h>#include <linux/kfifo.h>#include <linux/workqueue.h>#include <linux/acpi.h>#include <acpi/acpi_drivers.h>#include <acpi/acpi_bus.h>#include <asm/uaccess.h>#include <linux/sonypi.h>#include <linux/sony-laptop.h>#ifdef CONFIG_SONYPI_COMPAT#include <linux/poll.h>#include <linux/miscdevice.h>#endif#define DRV_PFX			"sony-laptop: "#define dprintk(msg...)		do {			\	if (debug) printk(KERN_WARNING DRV_PFX  msg);	\} while (0)#define SONY_LAPTOP_DRIVER_VERSION	"0.5"#define SONY_NC_CLASS		"sony-nc"#define SONY_NC_HID		"SNY5001"#define SONY_NC_DRIVER_NAME	"Sony Notebook Control Driver"#define SONY_PIC_CLASS		"sony-pic"#define SONY_PIC_HID		"SNY6001"#define SONY_PIC_DRIVER_NAME	"Sony Programmable IO Control Driver"MODULE_AUTHOR("Stelian Pop, Mattia Dongili");MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");MODULE_LICENSE("GPL");MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);static int debug;module_param(debug, int, 0);MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "		 "the development of this driver");static int no_spic;		/* = 0 */module_param(no_spic, int, 0444);MODULE_PARM_DESC(no_spic,		 "set this if you don't want to enable the SPIC device");static int compat;		/* = 0 */module_param(compat, int, 0444);MODULE_PARM_DESC(compat,		 "set this if you want to enable backward compatibility mode");static unsigned long mask = 0xffffffff;module_param(mask, ulong, 0644);MODULE_PARM_DESC(mask,		 "set this to the mask of event you want to enable (see doc)");static int camera;		/* = 0 */module_param(camera, int, 0444);MODULE_PARM_DESC(camera,		 "set this to 1 to enable Motion Eye camera controls "		 "(only use it if you have a C1VE or C1VN model)");#ifdef CONFIG_SONYPI_COMPATstatic int minor = -1;module_param(minor, int, 0);MODULE_PARM_DESC(minor,		 "minor number of the misc device for the SPIC compatibility code, "		 "default is -1 (automatic)");#endif/*********** Input Devices ***********/#define SONY_LAPTOP_BUF_SIZE	128struct sony_laptop_input_s {	atomic_t		users;	struct input_dev	*jog_dev;	struct input_dev	*key_dev;	struct kfifo		*fifo;	spinlock_t		fifo_lock;	struct workqueue_struct	*wq;};static struct sony_laptop_input_s sony_laptop_input = {	.users = ATOMIC_INIT(0),};struct sony_laptop_keypress {	struct input_dev *dev;	int key;};/* Correspondance table between sonypi events * and input layer indexes in the keymap */static int sony_laptop_input_index[] = {	-1,	/* no event */	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN */	-1,	/* SONYPI_EVENT_JOGDIAL_UP */	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */	-1,	/* SONYPI_EVENT_JOGDIAL_UP_PRESSED */	-1,	/* SONYPI_EVENT_JOGDIAL_PRESSED */	-1,	/* SONYPI_EVENT_JOGDIAL_RELEASED */	 0,	/* SONYPI_EVENT_CAPTURE_PRESSED */	 1,	/* SONYPI_EVENT_CAPTURE_RELEASED */	 2,	/* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */	 3,	/* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */	 4,	/* SONYPI_EVENT_FNKEY_ESC */	 5,	/* SONYPI_EVENT_FNKEY_F1 */	 6,	/* SONYPI_EVENT_FNKEY_F2 */	 7,	/* SONYPI_EVENT_FNKEY_F3 */	 8,	/* SONYPI_EVENT_FNKEY_F4 */	 9,	/* SONYPI_EVENT_FNKEY_F5 */	10,	/* SONYPI_EVENT_FNKEY_F6 */	11,	/* SONYPI_EVENT_FNKEY_F7 */	12,	/* SONYPI_EVENT_FNKEY_F8 */	13,	/* SONYPI_EVENT_FNKEY_F9 */	14,	/* SONYPI_EVENT_FNKEY_F10 */	15,	/* SONYPI_EVENT_FNKEY_F11 */	16,	/* SONYPI_EVENT_FNKEY_F12 */	17,	/* SONYPI_EVENT_FNKEY_1 */	18,	/* SONYPI_EVENT_FNKEY_2 */	19,	/* SONYPI_EVENT_FNKEY_D */	20,	/* SONYPI_EVENT_FNKEY_E */	21,	/* SONYPI_EVENT_FNKEY_F */	22,	/* SONYPI_EVENT_FNKEY_S */	23,	/* SONYPI_EVENT_FNKEY_B */	24,	/* SONYPI_EVENT_BLUETOOTH_PRESSED */	25,	/* SONYPI_EVENT_PKEY_P1 */	26,	/* SONYPI_EVENT_PKEY_P2 */	27,	/* SONYPI_EVENT_PKEY_P3 */	28,	/* SONYPI_EVENT_BACK_PRESSED */	-1,	/* SONYPI_EVENT_LID_CLOSED */	-1,	/* SONYPI_EVENT_LID_OPENED */	29,	/* SONYPI_EVENT_BLUETOOTH_ON */	30,	/* SONYPI_EVENT_BLUETOOTH_OFF */	31,	/* SONYPI_EVENT_HELP_PRESSED */	32,	/* SONYPI_EVENT_FNKEY_ONLY */	33,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN */	34,	/* SONYPI_EVENT_JOGDIAL_FAST_UP */	35,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */	36,	/* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */	37,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */	38,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP */	39,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */	40,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */	41,	/* SONYPI_EVENT_ZOOM_PRESSED */	42,	/* SONYPI_EVENT_THUMBPHRASE_PRESSED */	43,	/* SONYPI_EVENT_MEYE_FACE */	44,	/* SONYPI_EVENT_MEYE_OPPOSITE */	45,	/* SONYPI_EVENT_MEMORYSTICK_INSERT */	46,	/* SONYPI_EVENT_MEMORYSTICK_EJECT */	-1,	/* SONYPI_EVENT_ANYBUTTON_RELEASED */	-1,	/* SONYPI_EVENT_BATTERY_INSERT */	-1,	/* SONYPI_EVENT_BATTERY_REMOVE */	-1,	/* SONYPI_EVENT_FNKEY_RELEASED */	47,	/* SONYPI_EVENT_WIRELESS_ON */	48,	/* SONYPI_EVENT_WIRELESS_OFF */};static int sony_laptop_input_keycode_map[] = {	KEY_CAMERA,	/*  0 SONYPI_EVENT_CAPTURE_PRESSED */	KEY_RESERVED,	/*  1 SONYPI_EVENT_CAPTURE_RELEASED */	KEY_RESERVED,	/*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */	KEY_RESERVED,	/*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */	KEY_FN_ESC,	/*  4 SONYPI_EVENT_FNKEY_ESC */	KEY_FN_F1,	/*  5 SONYPI_EVENT_FNKEY_F1 */	KEY_FN_F2,	/*  6 SONYPI_EVENT_FNKEY_F2 */	KEY_FN_F3,	/*  7 SONYPI_EVENT_FNKEY_F3 */	KEY_FN_F4,	/*  8 SONYPI_EVENT_FNKEY_F4 */	KEY_FN_F5,	/*  9 SONYPI_EVENT_FNKEY_F5 */	KEY_FN_F6,	/* 10 SONYPI_EVENT_FNKEY_F6 */	KEY_FN_F7,	/* 11 SONYPI_EVENT_FNKEY_F7 */	KEY_FN_F8,	/* 12 SONYPI_EVENT_FNKEY_F8 */	KEY_FN_F9,	/* 13 SONYPI_EVENT_FNKEY_F9 */	KEY_FN_F10,	/* 14 SONYPI_EVENT_FNKEY_F10 */	KEY_FN_F11,	/* 15 SONYPI_EVENT_FNKEY_F11 */	KEY_FN_F12,	/* 16 SONYPI_EVENT_FNKEY_F12 */	KEY_FN_F1,	/* 17 SONYPI_EVENT_FNKEY_1 */	KEY_FN_F2,	/* 18 SONYPI_EVENT_FNKEY_2 */	KEY_FN_D,	/* 19 SONYPI_EVENT_FNKEY_D */	KEY_FN_E,	/* 20 SONYPI_EVENT_FNKEY_E */	KEY_FN_F,	/* 21 SONYPI_EVENT_FNKEY_F */	KEY_FN_S,	/* 22 SONYPI_EVENT_FNKEY_S */	KEY_FN_B,	/* 23 SONYPI_EVENT_FNKEY_B */	KEY_BLUETOOTH,	/* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */	KEY_PROG1,	/* 25 SONYPI_EVENT_PKEY_P1 */	KEY_PROG2,	/* 26 SONYPI_EVENT_PKEY_P2 */	KEY_PROG3,	/* 27 SONYPI_EVENT_PKEY_P3 */	KEY_BACK,	/* 28 SONYPI_EVENT_BACK_PRESSED */	KEY_BLUETOOTH,	/* 29 SONYPI_EVENT_BLUETOOTH_ON */	KEY_BLUETOOTH,	/* 30 SONYPI_EVENT_BLUETOOTH_OFF */	KEY_HELP,	/* 31 SONYPI_EVENT_HELP_PRESSED */	KEY_FN,		/* 32 SONYPI_EVENT_FNKEY_ONLY */	KEY_RESERVED,	/* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */	KEY_RESERVED,	/* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */	KEY_RESERVED,	/* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */	KEY_RESERVED,	/* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */	KEY_RESERVED,	/* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */	KEY_RESERVED,	/* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */	KEY_RESERVED,	/* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */	KEY_RESERVED,	/* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */	KEY_ZOOM,	/* 41 SONYPI_EVENT_ZOOM_PRESSED */	BTN_THUMB,	/* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */	KEY_RESERVED,	/* 43 SONYPI_EVENT_MEYE_FACE */	KEY_RESERVED,	/* 44 SONYPI_EVENT_MEYE_OPPOSITE */	KEY_RESERVED,	/* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */	KEY_RESERVED,	/* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */	KEY_WLAN,	/* 47 SONYPI_EVENT_WIRELESS_ON */	KEY_WLAN,	/* 48 SONYPI_EVENT_WIRELESS_OFF */};/* release buttons after a short delay if pressed */static void do_sony_laptop_release_key(struct work_struct *work){	struct sony_laptop_keypress kp;	while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,			 sizeof(kp)) == sizeof(kp)) {		msleep(10);		input_report_key(kp.dev, kp.key, 0);		input_sync(kp.dev);	}}static DECLARE_WORK(sony_laptop_release_key_work,		do_sony_laptop_release_key);/* forward event to the input subsystem */static void sony_laptop_report_input_event(u8 event){	struct input_dev *jog_dev = sony_laptop_input.jog_dev;	struct input_dev *key_dev = sony_laptop_input.key_dev;	struct sony_laptop_keypress kp = { NULL };	if (event == SONYPI_EVENT_FNKEY_RELEASED) {		/* Nothing, not all VAIOs generate this event */		return;	}	/* report events */	switch (event) {	/* jog_dev events */	case SONYPI_EVENT_JOGDIAL_UP:	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:		input_report_rel(jog_dev, REL_WHEEL, 1);		input_sync(jog_dev);		return;	case SONYPI_EVENT_JOGDIAL_DOWN:	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:		input_report_rel(jog_dev, REL_WHEEL, -1);		input_sync(jog_dev);		return;	/* key_dev events */	case SONYPI_EVENT_JOGDIAL_PRESSED:		kp.key = BTN_MIDDLE;		kp.dev = jog_dev;		break;	default:		if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);			break;		}		if (sony_laptop_input_index[event] != -1) {			kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];			if (kp.key != KEY_UNKNOWN)				kp.dev = key_dev;		}		break;	}	if (kp.dev) {		input_report_key(kp.dev, kp.key, 1);		/* we emit the scancode so we can always remap the key */		input_event(kp.dev, EV_MSC, MSC_SCAN, event);		input_sync(kp.dev);		kfifo_put(sony_laptop_input.fifo,			  (unsigned char *)&kp, sizeof(kp));		if (!work_pending(&sony_laptop_release_key_work))			queue_work(sony_laptop_input.wq,					&sony_laptop_release_key_work);	} else		dprintk("unknown input event %.2x\n", event);}static int sony_laptop_setup_input(struct acpi_device *acpi_device){	struct input_dev *jog_dev;	struct input_dev *key_dev;	int i;	int error;	/* don't run again if already initialized */	if (atomic_add_return(1, &sony_laptop_input.users) > 1)		return 0;	/* kfifo */	spin_lock_init(&sony_laptop_input.fifo_lock);	sony_laptop_input.fifo =		kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,			    &sony_laptop_input.fifo_lock);	if (IS_ERR(sony_laptop_input.fifo)) {		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");		error = PTR_ERR(sony_laptop_input.fifo);		goto err_dec_users;	}	/* init workqueue */	sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");	if (!sony_laptop_input.wq) {		printk(KERN_ERR DRV_PFX				"Unabe to create workqueue.\n");		error = -ENXIO;		goto err_free_kfifo;	}	/* input keys */	key_dev = input_allocate_device();	if (!key_dev) {		error = -ENOMEM;		goto err_destroy_wq;	}	key_dev->name = "Sony Vaio Keys";	key_dev->id.bustype = BUS_ISA;	key_dev->id.vendor = PCI_VENDOR_ID_SONY;	key_dev->dev.parent = &acpi_device->dev;	/* Initialize the Input Drivers: special keys */	set_bit(EV_KEY, key_dev->evbit);	set_bit(EV_MSC, key_dev->evbit);	set_bit(MSC_SCAN, key_dev->mscbit);	key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);	key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);	key_dev->keycode = &sony_laptop_input_keycode_map;	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {		if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {			set_bit(sony_laptop_input_keycode_map[i],				key_dev->keybit);		}	}	error = input_register_device(key_dev);	if (error)		goto err_free_keydev;	sony_laptop_input.key_dev = key_dev;	/* jogdial */	jog_dev = input_allocate_device();	if (!jog_dev) {		error = -ENOMEM;		goto err_unregister_keydev;	}	jog_dev->name = "Sony Vaio Jogdial";	jog_dev->id.bustype = BUS_ISA;	jog_dev->id.vendor = PCI_VENDOR_ID_SONY;	key_dev->dev.parent = &acpi_device->dev;	jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);	jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);	jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);	error = input_register_device(jog_dev);	if (error)		goto err_free_jogdev;	sony_laptop_input.jog_dev = jog_dev;	return 0;err_free_jogdev:	input_free_device(jog_dev);err_unregister_keydev:	input_unregister_device(key_dev);	/* to avoid kref underflow below at input_free_device */	key_dev = NULL;err_free_keydev:	input_free_device(key_dev);err_destroy_wq:	destroy_workqueue(sony_laptop_input.wq);err_free_kfifo:	kfifo_free(sony_laptop_input.fifo);err_dec_users:	atomic_dec(&sony_laptop_input.users);	return error;}static void sony_laptop_remove_input(void){	/* cleanup only after the last user has gone */	if (!atomic_dec_and_test(&sony_laptop_input.users))		return;	/* flush workqueue first */	flush_workqueue(sony_laptop_input.wq);	/* destroy input devs */	input_unregister_device(sony_laptop_input.key_dev);	sony_laptop_input.key_dev = NULL;	if (sony_laptop_input.jog_dev) {		input_unregister_device(sony_laptop_input.jog_dev);		sony_laptop_input.jog_dev = NULL;	}	destroy_workqueue(sony_laptop_input.wq);	kfifo_free(sony_laptop_input.fifo);}/*********** Platform Device ***********/static atomic_t sony_pf_users = ATOMIC_INIT(0);static struct platform_driver sony_pf_driver = {	.driver = {		   .name = "sony-laptop",		   .owner = THIS_MODULE,		   }};static struct platform_device *sony_pf_device;static int sony_pf_add(void){	int ret = 0;	/* don't run again if already initialized */	if (atomic_add_return(1, &sony_pf_users) > 1)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -