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

📄 video.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	active_device_list = kmalloc((1 +				      dod->package.count) *				     sizeof(struct					    acpi_video_enumerated_device),				     GFP_KERNEL);	if (!active_device_list) {		status = -ENOMEM;		goto out;	}	count = 0;	for (i = 0; i < dod->package.count; i++) {		obj = &dod->package.elements[i];		if (obj->type != ACPI_TYPE_INTEGER) {			printk(KERN_ERR PREFIX "Invalid _DOD data\n");			active_device_list[i].value.int_val =			    ACPI_VIDEO_HEAD_INVALID;		}		active_device_list[i].value.int_val = obj->integer.value;		active_device_list[i].bind_info = NULL;		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,				  (int)obj->integer.value));		count++;	}	active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;	kfree(video->attached_array);	video->attached_array = active_device_list;	video->attached_count = count;      out:	kfree(buffer.pointer);	return status;}/* *  Arg: *  	video	: video bus device  *  	event	: notify event * *  Return: *  	< 0	: error *   *	1. Find out the current active output device. *	2. Identify the next output device to switch to. *	3. call _DSS to do actual switch. */static int acpi_video_switch_output(struct acpi_video_bus *video, int event){	struct list_head *node;	struct acpi_video_device *dev = NULL;	struct acpi_video_device *dev_next = NULL;	struct acpi_video_device *dev_prev = NULL;	unsigned long state;	int status = 0;	mutex_lock(&video->device_list_lock);	list_for_each(node, &video->video_device_list) {		dev = container_of(node, struct acpi_video_device, entry);		status = acpi_video_device_get_state(dev, &state);		if (state & 0x2) {			dev_next = container_of(node->next,					struct acpi_video_device, entry);			dev_prev = container_of(node->prev,					struct acpi_video_device, entry);			goto out;		}	}	dev_next = container_of(node->next, struct acpi_video_device, entry);	dev_prev = container_of(node->prev, struct acpi_video_device, entry); out:	mutex_unlock(&video->device_list_lock);	switch (event) {	case ACPI_VIDEO_NOTIFY_CYCLE:	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:		acpi_video_device_set_state(dev, 0);		acpi_video_device_set_state(dev_next, 0x80000001);		break;	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:		acpi_video_device_set_state(dev, 0);		acpi_video_device_set_state(dev_prev, 0x80000001);	default:		break;	}	return status;}static intacpi_video_get_next_level(struct acpi_video_device *device,			  u32 level_current, u32 event){	int min, max, min_above, max_below, i, l, delta = 255;	max = max_below = 0;	min = min_above = 255;	/* Find closest level to level_current */	for (i = 0; i < device->brightness->count; i++) {		l = device->brightness->levels[i];		if (abs(l - level_current) < abs(delta)) {			delta = l - level_current;			if (!delta)				break;		}	}	/* Ajust level_current to closest available level */	level_current += delta;	for (i = 0; i < device->brightness->count; i++) {		l = device->brightness->levels[i];		if (l < min)			min = l;		if (l > max)			max = l;		if (l < min_above && l > level_current)			min_above = l;		if (l > max_below && l < level_current)			max_below = l;	}	switch (event) {	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:		return (level_current < max) ? min_above : min;	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:		return (level_current < max) ? min_above : max;	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:		return (level_current > min) ? max_below : min;	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:		return 0;	default:		return level_current;	}}static voidacpi_video_switch_brightness(struct acpi_video_device *device, int event){	unsigned long level_current, level_next;	acpi_video_device_lcd_get_level_current(device, &level_current);	level_next = acpi_video_get_next_level(device, level_current, event);	acpi_video_device_lcd_set_level(device, level_next);}static intacpi_video_bus_get_devices(struct acpi_video_bus *video,			   struct acpi_device *device){	int status = 0;	struct acpi_device *dev;	acpi_video_device_enumerate(video);	list_for_each_entry(dev, &device->children, node) {		status = acpi_video_bus_get_one_device(dev, video);		if (ACPI_FAILURE(status)) {			ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));			continue;		}	}	return status;}static int acpi_video_bus_put_one_device(struct acpi_video_device *device){	acpi_status status;	struct acpi_video_bus *video;	if (!device || !device->video)		return -ENOENT;	video = device->video;	acpi_video_device_remove_fs(device->dev);	status = acpi_remove_notify_handler(device->dev->handle,					    ACPI_DEVICE_NOTIFY,					    acpi_video_device_notify);	backlight_device_unregister(device->backlight);	video_output_unregister(device->output_dev);	return 0;}static int acpi_video_bus_put_devices(struct acpi_video_bus *video){	int status;	struct acpi_video_device *dev, *next;	mutex_lock(&video->device_list_lock);	list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {		status = acpi_video_bus_put_one_device(dev);		if (ACPI_FAILURE(status))			printk(KERN_WARNING PREFIX			       "hhuuhhuu bug in acpi video driver.\n");		if (dev->brightness) {			kfree(dev->brightness->levels);			kfree(dev->brightness);		}		list_del(&dev->entry);		kfree(dev);	}	mutex_unlock(&video->device_list_lock);	return 0;}/* acpi_video interface */static int acpi_video_bus_start_devices(struct acpi_video_bus *video){	return acpi_video_bus_DOS(video, 0, 0);}static int acpi_video_bus_stop_devices(struct acpi_video_bus *video){	return acpi_video_bus_DOS(video, 0, 1);}static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data){	struct acpi_video_bus *video = data;	struct acpi_device *device = NULL;	struct input_dev *input;	int keycode;	if (!video)		return;	device = video->device;	input = video->input;	switch (event) {	case ACPI_VIDEO_NOTIFY_SWITCH:	/* User requested a switch,					 * most likely via hotkey. */		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_SWITCHVIDEOMODE;		break;	case ACPI_VIDEO_NOTIFY_PROBE:	/* User plugged in or removed a video					 * connector. */		acpi_video_device_enumerate(video);		acpi_video_device_rebind(video);		acpi_video_switch_output(video, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_SWITCHVIDEOMODE;		break;	case ACPI_VIDEO_NOTIFY_CYCLE:	/* Cycle Display output hotkey pressed. */		acpi_video_switch_output(video, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_SWITCHVIDEOMODE;		break;	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:	/* Next Display output hotkey pressed. */		acpi_video_switch_output(video, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_VIDEO_NEXT;		break;	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:	/* previous Display output hotkey pressed. */		acpi_video_switch_output(video, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_VIDEO_PREV;		break;	default:		keycode = KEY_UNKNOWN;		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "Unsupported event [0x%x]\n", event));		break;	}	input_report_key(input, keycode, 1);	input_sync(input);	input_report_key(input, keycode, 0);	input_sync(input);	return;}static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data){	struct acpi_video_device *video_device = data;	struct acpi_device *device = NULL;	struct acpi_video_bus *bus;	struct input_dev *input;	int keycode;	if (!video_device)		return;	device = video_device->dev;	bus = video_device->video;	input = bus->input;	switch (event) {	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:	/* Cycle brightness */		acpi_video_switch_brightness(video_device, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_BRIGHTNESS_CYCLE;		break;	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:	/* Increase brightness */		acpi_video_switch_brightness(video_device, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_BRIGHTNESSUP;		break;	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:	/* Decrease brightness */		acpi_video_switch_brightness(video_device, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_BRIGHTNESSDOWN;		break;	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:	/* zero brightnesss */		acpi_video_switch_brightness(video_device, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_BRIGHTNESS_ZERO;		break;	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:	/* display device off */		acpi_video_switch_brightness(video_device, event);		acpi_bus_generate_proc_event(device, event, 0);		keycode = KEY_DISPLAY_OFF;		break;	default:		keycode = KEY_UNKNOWN;		ACPI_DEBUG_PRINT((ACPI_DB_INFO,				  "Unsupported event [0x%x]\n", event));		break;	}	input_report_key(input, keycode, 1);	input_sync(input);	input_report_key(input, keycode, 0);	input_sync(input);	return;}static int instance;static int acpi_video_bus_add(struct acpi_device *device){	acpi_status status;	struct acpi_video_bus *video;	struct input_dev *input;	int error;	video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);	if (!video)		return -ENOMEM;	/* a hack to fix the duplicate name "VID" problem on T61 */	if (!strcmp(device->pnp.bus_id, "VID")) {		if (instance)			device->pnp.bus_id[3] = '0' + instance;		instance ++;	}	video->device = device;	strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);	strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);	acpi_driver_data(device) = video;	acpi_video_bus_find_cap(video);	error = acpi_video_bus_check(video);	if (error)		goto err_free_video;	error = acpi_video_bus_add_fs(device);	if (error)		goto err_free_video;	mutex_init(&video->device_list_lock);	INIT_LIST_HEAD(&video->video_device_list);	acpi_video_bus_get_devices(video, device);	acpi_video_bus_start_devices(video);	status = acpi_install_notify_handler(device->handle,					     ACPI_DEVICE_NOTIFY,					     acpi_video_bus_notify, video);	if (ACPI_FAILURE(status)) {		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,				  "Error installing notify handler\n"));		error = -ENODEV;		goto err_stop_video;	}	video->input = input = input_allocate_device();	if (!input) {		error = -ENOMEM;		goto err_uninstall_notify;	}	snprintf(video->phys, sizeof(video->phys),		"%s/video/input0", acpi_device_hid(video->device));	input->name = acpi_device_name(video->device);	input->phys = video->phys;	input->id.bustype = BUS_HOST;	input->id.product = 0x06;	input->dev.parent = &device->dev;	input->evbit[0] = BIT(EV_KEY);	set_bit(KEY_SWITCHVIDEOMODE, input->keybit);	set_bit(KEY_VIDEO_NEXT, input->keybit);	set_bit(KEY_VIDEO_PREV, input->keybit);	set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);	set_bit(KEY_BRIGHTNESSUP, input->keybit);	set_bit(KEY_BRIGHTNESSDOWN, input->keybit);	set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);	set_bit(KEY_DISPLAY_OFF, input->keybit);	set_bit(KEY_UNKNOWN, input->keybit);	error = input_register_device(input);	if (error)		goto err_free_input_dev;	printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",	       ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),	       video->flags.multihead ? "yes" : "no",	       video->flags.rom ? "yes" : "no",	       video->flags.post ? "yes" : "no");	return 0; err_free_input_dev:	input_free_device(input); err_uninstall_notify:	acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,				   acpi_video_bus_notify); err_stop_video:	acpi_video_bus_stop_devices(video);	acpi_video_bus_put_devices(video);	kfree(video->attached_array);	acpi_video_bus_remove_fs(device); err_free_video:	kfree(video);	acpi_driver_data(device) = NULL;	return error;}static int acpi_video_bus_remove(struct acpi_device *device, int type){	acpi_status status = 0;	struct acpi_video_bus *video = NULL;	if (!device || !acpi_driver_data(device))		return -EINVAL;	video = acpi_driver_data(device);	acpi_video_bus_stop_devices(video);	status = acpi_remove_notify_handler(video->device->handle,					    ACPI_DEVICE_NOTIFY,					    acpi_video_bus_notify);	acpi_video_bus_put_devices(video);	acpi_video_bus_remove_fs(device);	input_unregister_device(video->input);	kfree(video->attached_array);	kfree(video);	return 0;}static int __init acpi_video_init(void){	int result = 0;	/*	   acpi_dbg_level = 0xFFFFFFFF;	   acpi_dbg_layer = 0x08000000;	 */	acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);	if (!acpi_video_dir)		return -ENODEV;	acpi_video_dir->owner = THIS_MODULE;	result = acpi_bus_register_driver(&acpi_video_bus);	if (result < 0) {		remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);		return -ENODEV;	}	return 0;}static void __exit acpi_video_exit(void){	acpi_bus_unregister_driver(&acpi_video_bus);	remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);	return;}module_init(acpi_video_init);module_exit(acpi_video_exit);

⌨️ 快捷键说明

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