Free Electrons

Embedded Linux Experts

 * Copyright 2012 Red Hat, Inc <>
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>

static struct acpi_table_bgrt *bgrt_tab;
static struct kobject *bgrt_kobj;

struct bmp_header {
	u16 id;
	u32 size;
} __attribute ((packed));

static struct bmp_header bmp_header;

static ssize_t show_version(struct device *dev,
			    struct device_attribute *attr, char *buf)
	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version);
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);

static ssize_t show_status(struct device *dev,
			   struct device_attribute *attr, char *buf)
	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status);
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);

static ssize_t show_type(struct device *dev,
			 struct device_attribute *attr, char *buf)
	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type);
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);

static ssize_t show_xoffset(struct device *dev,
			    struct device_attribute *attr, char *buf)
	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x);
static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL);

static ssize_t show_yoffset(struct device *dev,
			    struct device_attribute *attr, char *buf)
	return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y);
static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL);

static ssize_t show_image(struct file *file, struct kobject *kobj,
	       struct bin_attribute *attr, char *buf, loff_t off, size_t count)
	int size = attr->size;
	void __iomem *image = attr->private;

	if (off >= size) {
		count = 0;
	} else {
		if (off + count > size)
			count = size - off;

		memcpy_fromio(buf, image+off, count);

	return count;

static struct bin_attribute image_attr = {
	.attr = {
		.name = "image",
		.mode = S_IRUGO,
	.read = show_image,

static struct attribute *bgrt_attributes[] = {

static struct attribute_group bgrt_attribute_group = {
	.attrs = bgrt_attributes,

static int __init bgrt_init(void)
	acpi_status status;
	int ret;
	void __iomem *bgrt;

	if (acpi_disabled)
		return -ENODEV;

	status = acpi_get_table("BGRT", 0,
				(struct acpi_table_header **)&bgrt_tab);

	if (ACPI_FAILURE(status))
		return -ENODEV;


	bgrt = ioremap(bgrt_tab->image_address, sizeof(struct bmp_header));

	if (!bgrt) {
		ret = -EINVAL;
		goto out_err;

	memcpy_fromio(&bmp_header, bgrt, sizeof(bmp_header));
	image_attr.size = bmp_header.size;

	image_attr.private = ioremap(bgrt_tab->image_address, image_attr.size);

	if (!image_attr.private) {
		ret = -EINVAL;
		goto out_err;

	bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj);
	if (!bgrt_kobj) {
		ret = -EINVAL;
		goto out_iounmap;

	ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group);
	if (ret)
		goto out_kobject;

	ret = sysfs_create_bin_file(bgrt_kobj, &image_attr);
	if (ret)
		goto out_group;

	return 0;

	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
	return ret;

static void __exit bgrt_exit(void)
	sysfs_remove_group(bgrt_kobj, &bgrt_attribute_group);
	sysfs_remove_bin_file(bgrt_kobj, &image_attr);


MODULE_AUTHOR("Matthew Garrett");
MODULE_DESCRIPTION("BGRT boot graphic support");