📄 video.c
字号:
else { entry->proc_fops = &acpi_video_device_EDID_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } return 0;}static int acpi_video_device_remove_fs(struct acpi_device *device){ struct acpi_video_device *vid_dev; vid_dev = acpi_driver_data(device); if (!vid_dev || !vid_dev->video || !vid_dev->video->dir) return -ENODEV; if (acpi_device_dir(device)) { remove_proc_entry("info", acpi_device_dir(device)); remove_proc_entry("state", acpi_device_dir(device)); remove_proc_entry("brightness", acpi_device_dir(device)); remove_proc_entry("EDID", acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir); acpi_device_dir(device) = NULL; } return 0;}/* video bus */static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset){ struct acpi_video_bus *video = seq->private; if (!video) goto end; seq_printf(seq, "Switching heads: %s\n", video->flags.multihead ? "yes" : "no"); seq_printf(seq, "Video ROM: %s\n", video->flags.rom ? "yes" : "no"); seq_printf(seq, "Device to be POSTed on boot: %s\n", video->flags.post ? "yes" : "no"); end: return 0;}static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_video_bus_info_seq_show, PDE(inode)->data);}static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset){ struct acpi_video_bus *video = seq->private; if (!video) goto end; printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__); seq_printf(seq, "<TODO>\n"); end: return 0;}static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);}static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset){ struct acpi_video_bus *video = seq->private; unsigned long options; int status; if (!video) goto end; status = acpi_video_bus_POST_options(video, &options); if (ACPI_SUCCESS(status)) { if (!(options & 1)) { printk(KERN_WARNING PREFIX "The motherboard VGA device is not listed as a possible POST device.\n"); printk(KERN_WARNING PREFIX "This indicates a BIOS bug. Please contact the manufacturer.\n"); } printk("%lx\n", options); seq_printf(seq, "can POST: <integrated video>"); if (options & 2) seq_printf(seq, " <PCI video>"); if (options & 4) seq_printf(seq, " <AGP video>"); seq_putc(seq, '\n'); } else seq_printf(seq, "<not supported>\n"); end: return 0;}static intacpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_video_bus_POST_info_seq_show, PDE(inode)->data);}static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset){ struct acpi_video_bus *video = seq->private; int status; unsigned long id; if (!video) goto end; status = acpi_video_bus_get_POST(video, &id); if (!ACPI_SUCCESS(status)) { seq_printf(seq, "<not supported>\n"); goto end; } seq_printf(seq, "device POSTed is <%s>\n", device_decode[id & 3]); end: return 0;}static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset){ struct acpi_video_bus *video = seq->private; seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting); return 0;}static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_video_bus_POST_seq_show, PDE(inode)->data);}static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file){ return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);}static ssize_tacpi_video_bus_write_POST(struct file *file, const char __user * buffer, size_t count, loff_t * data){ int status; struct seq_file *m = file->private_data; struct acpi_video_bus *video = m->private; char str[12] = { 0 }; unsigned long opt, options; if (!video || count + 1 > sizeof str) return -EINVAL; status = acpi_video_bus_POST_options(video, &options); if (!ACPI_SUCCESS(status)) return -EINVAL; if (copy_from_user(str, buffer, count)) return -EFAULT; str[count] = 0; opt = strtoul(str, NULL, 0); if (opt > 3) return -EFAULT; /* just in case an OEM 'forgot' the motherboard... */ options |= 1; if (options & (1ul << opt)) { status = acpi_video_bus_set_POST(video, opt); if (!ACPI_SUCCESS(status)) return -EFAULT; } return count;}static ssize_tacpi_video_bus_write_DOS(struct file *file, const char __user * buffer, size_t count, loff_t * data){ int status; struct seq_file *m = file->private_data; struct acpi_video_bus *video = m->private; char str[12] = { 0 }; unsigned long opt; if (!video || count + 1 > sizeof str) return -EINVAL; if (copy_from_user(str, buffer, count)) return -EFAULT; str[count] = 0; opt = strtoul(str, NULL, 0); if (opt > 7) return -EFAULT; status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2); if (!ACPI_SUCCESS(status)) return -EFAULT; return count;}static int acpi_video_bus_add_fs(struct acpi_device *device){ struct proc_dir_entry *entry = NULL; struct acpi_video_bus *video; video = acpi_driver_data(device); if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_video_dir); if (!acpi_device_dir(device)) return -ENODEV; video->dir = acpi_device_dir(device); acpi_device_dir(device)->owner = THIS_MODULE; } /* 'info' [R] */ entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_video_bus_info_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'ROM' [R] */ entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_video_bus_ROM_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'POST_info' [R] */ entry = create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_video_bus_POST_info_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'POST' [R/W] */ entry = create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR, acpi_device_dir(device)); if (!entry) return -ENODEV; else { acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; entry->proc_fops = &acpi_video_bus_POST_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } /* 'DOS' [R/W] */ entry = create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR, acpi_device_dir(device)); if (!entry) return -ENODEV; else { acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; entry->proc_fops = &acpi_video_bus_DOS_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } return 0;}static int acpi_video_bus_remove_fs(struct acpi_device *device){ struct acpi_video_bus *video; video = acpi_driver_data(device); if (acpi_device_dir(device)) { remove_proc_entry("info", acpi_device_dir(device)); remove_proc_entry("ROM", acpi_device_dir(device)); remove_proc_entry("POST_info", acpi_device_dir(device)); remove_proc_entry("POST", acpi_device_dir(device)); remove_proc_entry("DOS", acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_video_dir); acpi_device_dir(device) = NULL; } return 0;}/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- *//* device interface */static struct acpi_video_device_attrib*acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id){ int count; for(count = 0; count < video->attached_count; count++) if((video->attached_array[count].value.int_val & 0xffff) == device_id) return &(video->attached_array[count].value.attrib); return NULL;}static intacpi_video_bus_get_one_device(struct acpi_device *device, struct acpi_video_bus *video){ unsigned long device_id; int status; struct acpi_video_device *data; struct acpi_video_device_attrib* attribute; if (!device || !video) return -EINVAL; status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id); if (ACPI_SUCCESS(status)) { data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL); if (!data) return -ENOMEM; strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS); acpi_driver_data(device) = data; data->device_id = device_id; data->video = video; data->dev = device; attribute = acpi_video_get_device_attr(video, device_id); if((attribute != NULL) && attribute->device_id_scheme) { switch (attribute->display_type) { case ACPI_VIDEO_DISPLAY_CRT: data->flags.crt = 1; break; case ACPI_VIDEO_DISPLAY_TV: data->flags.tvout = 1; break; case ACPI_VIDEO_DISPLAY_DVI: data->flags.dvi = 1; break; case ACPI_VIDEO_DISPLAY_LCD: data->flags.lcd = 1; break; default: data->flags.unknown = 1; break; } if(attribute->bios_can_detect) data->flags.bios = 1; } else data->flags.unknown = 1; acpi_video_device_bind(video, data); acpi_video_device_find_cap(data); status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify, data); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error installing notify handler\n")); if(data->brightness) kfree(data->brightness->levels); kfree(data->brightness); kfree(data); return -ENODEV; } mutex_lock(&video->device_list_lock); list_add_tail(&data->entry, &video->video_device_list); mutex_unlock(&video->device_list_lock); acpi_video_device_add_fs(device); return 0; } return -ENOENT;}/* * Arg: * video : video bus device * * Return: * none * * Enumerate the video device list of the video bus, * bind the ids with the corresponding video devices * under the video bus. */static void acpi_video_device_rebind(struct acpi_video_bus *video){ struct acpi_video_device *dev; mutex_lock(&video->device_list_lock); list_for_each_entry(dev, &video->video_device_list, entry) acpi_video_device_bind(video, dev); mutex_unlock(&video->device_list_lock);}/* * Arg: * video : video bus device * device : video output device under the video * bus * * Return: * none * * Bind the ids with the corresponding video devices * under the video bus. */static voidacpi_video_device_bind(struct acpi_video_bus *video, struct acpi_video_device *device){ int i;#define IDS_VAL(i) video->attached_array[i].value.int_val#define IDS_BIND(i) video->attached_array[i].bind_info for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID && i < video->attached_count; i++) { if (device->device_id == (IDS_VAL(i) & 0xffff)) { IDS_BIND(i) = device; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i)); } }#undef IDS_VAL#undef IDS_BIND}/* * Arg: * video : video bus device * * Return: * < 0 : error * * Call _DOD to enumerate all devices attached to display adapter * */static int acpi_video_device_enumerate(struct acpi_video_bus *video){ int status; int count; int i; struct acpi_video_enumerated_device *active_device_list; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *dod = NULL; union acpi_object *obj; status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer); if (!ACPI_SUCCESS(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD")); return status; } dod = buffer.pointer; if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) { ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data")); status = -EFAULT; goto out; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n", dod->package.count));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -