1 /* 2 * Copyright 2012 Red Hat, Inc <mjg@redhat.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/init.h> 12 #include <linux/device.h> 13 #include <linux/sysfs.h> 14 #include <acpi/acpi.h> 15 #include <acpi/acpi_bus.h> 16 17 static struct acpi_table_bgrt *bgrt_tab; 18 static struct kobject *bgrt_kobj; 19 20 struct bmp_header { 21 u16 id; 22 u32 size; 23 } __attribute ((packed)); 24 25 static struct bmp_header bmp_header; 26 27 static ssize_t show_version(struct device *dev, 28 struct device_attribute *attr, char *buf) 29 { 30 return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version); 31 } 32 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); 33 34 static ssize_t show_status(struct device *dev, 35 struct device_attribute *attr, char *buf) 36 { 37 return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status); 38 } 39 static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); 40 41 static ssize_t show_type(struct device *dev, 42 struct device_attribute *attr, char *buf) 43 { 44 return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type); 45 } 46 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); 47 48 static ssize_t show_xoffset(struct device *dev, 49 struct device_attribute *attr, char *buf) 50 { 51 return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x); 52 } 53 static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL); 54 55 static ssize_t show_yoffset(struct device *dev, 56 struct device_attribute *attr, char *buf) 57 { 58 return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y); 59 } 60 static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL); 61 62 static ssize_t show_image(struct file *file, struct kobject *kobj, 63 struct bin_attribute *attr, char *buf, loff_t off, size_t count) 64 { 65 int size = attr->size; 66 void __iomem *image = attr->private; 67 68 if (off >= size) { 69 count = 0; 70 } else { 71 if (off + count > size) 72 count = size - off; 73 74 memcpy_fromio(buf, image+off, count); 75 } 76 77 return count; 78 } 79 80 static struct bin_attribute image_attr = { 81 .attr = { 82 .name = "image", 83 .mode = S_IRUGO, 84 }, 85 .read = show_image, 86 }; 87 88 static struct attribute *bgrt_attributes[] = { 89 &dev_attr_version.attr, 90 &dev_attr_status.attr, 91 &dev_attr_type.attr, 92 &dev_attr_xoffset.attr, 93 &dev_attr_yoffset.attr, 94 NULL, 95 }; 96 97 static struct attribute_group bgrt_attribute_group = { 98 .attrs = bgrt_attributes, 99 }; 100 101 static int __init bgrt_init(void) 102 { 103 acpi_status status; 104 int ret; 105 void __iomem *bgrt; 106 107 if (acpi_disabled) 108 return -ENODEV; 109 110 status = acpi_get_table("BGRT", 0, 111 (struct acpi_table_header **)&bgrt_tab); 112 113 if (ACPI_FAILURE(status)) 114 return -ENODEV; 115 116 sysfs_bin_attr_init(&image_attr); 117 118 bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header)); 119 120 if (!bgrt) { 121 ret = -EINVAL; 122 goto out_err; 123 } 124 125 memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header)); 126 image_attr.size = bmp_header.size; 127 iounmap(bgrt); 128 129 image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size); 130 131 if (!image_attr.private) { 132 ret = -EINVAL; 133 goto out_err; 134 } 135 136 137 bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); 138 if (!bgrt_kobj) { 139 ret = -EINVAL; 140 goto out_iounmap; 141 } 142 143 ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group); 144 if (ret) 145 goto out_kobject; 146 147 ret = sysfs_create_bin_file(bgrt_kobj, &image_attr); 148 if (ret) 149 goto out_group; 150 151 return 0; 152 153 out_group: 154 sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group); 155 out_kobject: 156 kobject_put(bgrt_kobj); 157 out_iounmap: 158 iounmap(image_attr.private); 159 out_err: 160 return ret; 161 } 162 163 static void __exit bgrt_exit(void) 164 { 165 iounmap(image_attr.private); 166 sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group); 167 sysfs_remove_bin_file(bgrt_kobj, &image_attr); 168 } 169 170 module_init(bgrt_init); 171 module_exit(bgrt_exit); 172 173 MODULE_AUTHOR("Matthew Garrett"); 174 MODULE_DESCRIPTION("BGRT boot graphic support"); 175 MODULE_LICENSE("GPL"); 176