#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/suspend.h>
+#include <acpi/video.h>
#define PREFIX "ACPI: "
#define MAX_NAME_LEN 20
-#define ACPI_VIDEO_DISPLAY_CRT 1
-#define ACPI_VIDEO_DISPLAY_TV 2
-#define ACPI_VIDEO_DISPLAY_DVI 3
-#define ACPI_VIDEO_DISPLAY_LCD 4
-
#define _COMPONENT ACPI_VIDEO_COMPONENT
ACPI_MODULE_NAME("video");
struct acpi_video_bus_flags flags;
struct list_head video_device_list;
struct mutex device_list_lock; /* protects video_device_list */
+#ifdef CONFIG_ACPI_PROCFS
struct proc_dir_entry *dir;
+#endif
struct input_dev *input;
char phys[32]; /* for input device */
struct notifier_block pm_nb;
struct output_device *output_dev;
};
+#ifdef CONFIG_ACPI_PROCFS
/* bus */
static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
static const struct file_operations acpi_video_bus_info_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif /* CONFIG_ACPI_PROCFS */
static const char device_decode[][30] = {
"motherboard VGA device",
/* device */
-static int
-acpi_video_device_query(struct acpi_video_device *device, unsigned long long *state)
-{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_DGS", NULL, state);
-
- return status;
-}
-
static int
acpi_video_device_get_state(struct acpi_video_device *device,
unsigned long long *state)
/* bus */
-static int
-acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
-{
- int status;
- unsigned long long tmp;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
-
-
- arg0.integer.value = option;
-
- status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp);
- if (ACPI_SUCCESS(status))
- status = tmp ? (-EINVAL) : (AE_OK);
-
- return status;
-}
-
-static int
-acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
-{
- int status;
-
- status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
-
- return status;
-}
-
-static int
-acpi_video_bus_POST_options(struct acpi_video_bus *video,
- unsigned long long *options)
-{
- int status;
-
- status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options);
- *options &= 3;
-
- return status;
-}
-
/*
* Arg:
* video : video bus device pointer
result = acpi_video_init_brightness(device);
if (result)
return;
- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
if (!name)
return;
+ count++;
- sprintf(name, "acpi_video%d", count++);
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = device->brightness->count - 3;
device->backlight = backlight_device_register(name, NULL, device,
if (device->cap._DCS && device->cap._DSS) {
static int count;
char *name;
- name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
if (!name)
return;
- sprintf(name, "acpi_video%d", count++);
+ count++;
device->output_dev = video_output_register(name,
NULL, device, &acpi_output_properties);
kfree(name);
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_video_dir;
PDE(inode)->data);
}
+static int
+acpi_video_device_query(struct acpi_video_device *device,
+ unsigned long long *state)
+{
+ int status;
+
+ status = acpi_evaluate_integer(device->dev->handle, "_DGS",
+ NULL, state);
+
+ return status;
+}
+
static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
{
int status;
return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
}
+static int
+acpi_video_bus_POST_options(struct acpi_video_bus *video,
+ unsigned long long *options)
+{
+ int status;
+
+ status = acpi_evaluate_integer(video->device->handle, "_VPO",
+ NULL, options);
+ *options &= 3;
+
+ return status;
+}
+
static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = seq->private;
PDE(inode)->data);
}
+static int
+acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long long *id)
+{
+ int status;
+
+ status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
+
+ return status;
+}
+
static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = seq->private;
return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
}
+static int
+acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
+{
+ int status;
+ unsigned long long tmp;
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list args = { 1, &arg0 };
+
+
+ arg0.integer.value = option;
+
+ status = acpi_evaluate_integer(video->device->handle, "_SPD",
+ &args, &tmp);
+ if (ACPI_SUCCESS(status))
+ status = tmp ? (-EINVAL) : (AE_OK);
+
+ return status;
+}
+
static ssize_t
acpi_video_bus_write_POST(struct file *file,
const char __user * buffer,
return 0;
}
+#else
+static inline int acpi_video_device_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_video_device_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_video_bus_add_fs(struct acpi_device *device)
+{
+ return 0;
+}
+static inline int acpi_video_bus_remove_fs(struct acpi_device *device)
+{
+ return 0;
+}
+#endif /* CONFIG_ACPI_PROCFS */
/* --------------------------------------------------------------------------
Driver Interface
return NULL;
}
+static int
+acpi_video_get_device_type(struct acpi_video_bus *video,
+ unsigned long device_id)
+{
+ struct acpi_video_enumerated_device *ids;
+ int i;
+
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if ((ids->value.int_val & 0xffff) == device_id)
+ return ids->value.int_val;
+ }
+
+ return 0;
+}
+
static int
acpi_video_bus_get_one_device(struct acpi_device *device,
struct acpi_video_bus *video)
{
unsigned long long device_id;
- int status;
+ int status, device_type;
struct acpi_video_device *data;
struct acpi_video_device_attrib* attribute;
}
if(attribute->bios_can_detect)
data->flags.bios = 1;
- } else
- data->flags.unknown = 1;
+ } else {
+ /* Check for legacy IDs */
+ device_type = acpi_video_get_device_type(video,
+ device_id);
+ /* Ignore bits 16 and 18-20 */
+ switch (device_type & 0xffe2ffff) {
+ case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+ data->flags.crt = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+ data->flags.lcd = 1;
+ break;
+ case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+ data->flags.tvout = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ }
+ }
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
return result;
}
+int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
+ void **edid)
+{
+ struct acpi_video_bus *video;
+ struct acpi_video_device *video_device;
+ union acpi_object *buffer = NULL;
+ acpi_status status;
+ int i, length;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ video = acpi_driver_data(device);
+
+ for (i = 0; i < video->attached_count; i++) {
+ video_device = video->attached_array[i].bind_info;
+ length = 256;
+
+ if (!video_device)
+ continue;
+
+ if (type) {
+ switch (type) {
+ case ACPI_VIDEO_DISPLAY_CRT:
+ if (!video_device->flags.crt)
+ continue;
+ break;
+ case ACPI_VIDEO_DISPLAY_TV:
+ if (!video_device->flags.tvout)
+ continue;
+ break;
+ case ACPI_VIDEO_DISPLAY_DVI:
+ if (!video_device->flags.dvi)
+ continue;
+ break;
+ case ACPI_VIDEO_DISPLAY_LCD:
+ if (!video_device->flags.lcd)
+ continue;
+ break;
+ }
+ } else if (video_device->device_id != device_id) {
+ continue;
+ }
+
+ status = acpi_video_device_EDID(video_device, &buffer, length);
+
+ if (ACPI_FAILURE(status) || !buffer ||
+ buffer->type != ACPI_TYPE_BUFFER) {
+ length = 128;
+ status = acpi_video_device_EDID(video_device, &buffer,
+ length);
+ if (ACPI_FAILURE(status) || !buffer ||
+ buffer->type != ACPI_TYPE_BUFFER) {
+ continue;
+ }
+ }
+
+ *edid = buffer->buffer.pointer;
+ return length;
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_video_get_edid);
+
static int
acpi_video_bus_get_devices(struct acpi_video_bus *video,
struct acpi_device *device)
return 0;
}
+#ifdef CONFIG_ACPI_PROCFS
acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
if (!acpi_video_dir)
return -ENODEV;
+#endif
result = acpi_bus_register_driver(&acpi_video_bus);
if (result < 0) {
}
acpi_bus_unregister_driver(&acpi_video_bus);
+#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+#endif
register_count = 0;