Skip to content

Commit

Permalink
video:sunxi:disp: add version ioctl
Browse files Browse the repository at this point in the history
* introduce some version macros to the ioctl header.
* introduce a new versioning ioctl.
* pr_info the version on load.
* verbosely warn when user application is not using the version
  ioctl before doing anything else with /dev/disp
* verbosely warn about the bumpy road ahead, and point to the
  wiki when doing so.

Signed-off-by: Luc Verhaegen <libv@skynet.be>
  • Loading branch information
libv committed Oct 30, 2012
1 parent 7e54df3 commit 0294e5b
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 7 deletions.
67 changes: 67 additions & 0 deletions Documentation/sunxi/disp/version.c
@@ -0,0 +1,67 @@
/*
* Simple example to ease users of /dev/disp into using the new but mandatory
* versioning handshake ioctl. No license or copyright claims made.
*
* Use
* gcc -Wall -I../../../include -o disp_version version.c
* to compile this.
*
* Author: Luc Verhaegen <libv@skynet.be>
*/

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <asm/types.h>

#include <video/sunxi_disp_ioctl.h>

int
main(int argc, char *argv[])
{
int fd = open("/dev/disp", O_RDWR);
int ret, tmp, width, height;

if (fd == -1) {
fprintf(stderr, "Error: Failed to open /dev/mali: %s\n",
strerror(errno));
return errno;
}

tmp = SUNXI_DISP_VERSION;
ret = ioctl(fd, DISP_CMD_VERSION, &tmp);
if (ret < 0) {
fprintf(stderr, "Error: ioctl(VERSION) failed: %s\n",
strerror(-ret));
return ret;
}

printf("disp kernel module version is %d.%d\n",
ret >> 16, ret & 0xFFFF);

tmp = 0;
ret = ioctl(fd, DISP_CMD_SCN_GET_WIDTH, &tmp);
if (ret) {
fprintf(stderr, "Error: ioctl(SCN_GET_WIDTH) failed: %s\n",
strerror(ret));
return ret;
}

width = ret;

tmp = 0;
ret = ioctl(fd, DISP_CMD_SCN_GET_HEIGHT, &tmp);
if (ret) {
fprintf(stderr, "Error: ioctl(SCN_GET_HEIGHT) failed: %s\n",
strerror(ret));
return ret;
}

height = ret;

printf("DISP dimensions are %dx%d\n", width, height);

return 0;
}
85 changes: 79 additions & 6 deletions drivers/video/sunxi/disp/dev_disp.c
@@ -1,6 +1,7 @@
/*
* copyright (c) 2007-2012 Allwinner Technology Co., Ltd.
* copyright (c) 2007-2012 Danling <danliang@allwinnertech.com>
* copyright (c) 2012 Luc Verhaegen <libv@skynet.be>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
Expand Down Expand Up @@ -387,7 +388,7 @@ disp_mem_release(int sel)

}

int disp_mmap(struct file *file, struct vm_area_struct *vma)
int disp_mmap(struct file *filp, struct vm_area_struct *vma)
{
// - PAGE_OFFSET;
unsigned long physics = g_disp_mm[g_disp_mm_sel].mem_start;
Expand All @@ -401,23 +402,58 @@ int disp_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}

int disp_open(struct inode *inode, struct file *file)
/*
*
*/
struct dev_disp_data {
/* Version of the user of /dev/disp */
#define SUNXI_DISP_VERSION_PENDING -1
#define SUNXI_DISP_VERSION_SKIPPED -2
int version;
};

int disp_open(struct inode *inode, struct file *filp)
{
struct dev_disp_data *data =
kmalloc(sizeof(struct dev_disp_data), GFP_KERNEL);
static bool warned;

if (!data)
return -ENOMEM;

data->version = SUNXI_DISP_VERSION_PENDING;

filp->private_data = data;

if (!warned) {
pr_warn("Warning: this sunxi disp driver will see significant "
"redesign.\n");
pr_warn("Applications using /dev/disp directly will break.\n");
pr_warn("For more information visit: "
"http://linux-sunxi.org/Sunxi_disp_driver\n");
warned = true;
}

return 0;
}

int disp_release(struct inode *inode, struct file *file)
int disp_release(struct inode *inode, struct file *filp)
{
struct dev_disp_data *data = filp->private_data;

kfree(data);
filp->private_data = NULL;

return 0;
}

ssize_t disp_read(struct file *file, char __user *buf, size_t count,
ssize_t disp_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
return 0;
}

ssize_t disp_write(struct file *file, const char __user *buf, size_t count,
ssize_t disp_write(struct file *filp, const char __user *buf, size_t count,
loff_t *ppos)
{
return 0;
Expand Down Expand Up @@ -467,6 +503,9 @@ static int __devinit disp_probe(struct platform_device *pdev)
__inf("PIO base 0x%08x\n", info->base_pioc);
__inf("PWM base 0x%08x\n", info->base_pwm);

pr_info("sunxi disp driver loaded (/dev/disp api %d.%d)\n",
SUNXI_DISP_VERSION_MAJOR, SUNXI_DISP_VERSION_MINOR);

return 0;
}

Expand Down Expand Up @@ -605,8 +644,9 @@ disp_shutdown(struct platform_device *pdev)
}
}

long disp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
long disp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct dev_disp_data *filp_data = filp->private_data;
unsigned long karg[4];
unsigned long ubuffer[4] = { 0 };
__s32 ret = 0;
Expand All @@ -622,6 +662,39 @@ long disp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ubuffer[2] = (*(unsigned long *)(karg + 2));
ubuffer[3] = (*(unsigned long *)(karg + 3));

/* Verify version handshake first. */
if (filp_data->version == SUNXI_DISP_VERSION_PENDING) {
if (cmd == DISP_CMD_VERSION) {
int version = *((int *) karg);

if (version < 0) {
pr_err("disp: process %d (%s) provided an "
"invalid version.\n",
current->pid, current->comm);
filp_data->version = SUNXI_DISP_VERSION_SKIPPED;
return -EINVAL;
}

if (version != SUNXI_DISP_VERSION)
pr_warn("disp: process %d (%s) has a different "
"version: %d.%d (vs. %d.%d)\n",
current->pid, current->comm,
SUNXI_DISP_VERSION_MAJOR_GET(version),
SUNXI_DISP_VERSION_MINOR_GET(version),
SUNXI_DISP_VERSION_MAJOR,
SUNXI_DISP_VERSION_MINOR);

/* Add compatibility checks here */

filp_data->version = version;
return SUNXI_DISP_VERSION;
} else {
pr_err("disp: process %d (%s) has skipped the version "
"handshake.\n", current->pid, current->comm);
filp_data->version = SUNXI_DISP_VERSION_SKIPPED;
}
}

if (cmd < DISP_CMD_FB_REQUEST) {
if ((ubuffer[0] != 0) && (ubuffer[0] != 1)) {
__wrn("para err in disp_ioctl, cmd = 0x%x,"
Expand Down
10 changes: 9 additions & 1 deletion include/video/sunxi_disp_ioctl.h
Expand Up @@ -22,6 +22,14 @@

#define __bool signed char

/* for tracking the ioctls API/ABI */
#define SUNXI_DISP_VERSION_MAJOR 1
#define SUNXI_DISP_VERSION_MINOR 0

#define SUNXI_DISP_VERSION ((SUNXI_DISP_VERSION_MAJOR << 16) | SUNXI_DISP_VERSION_MINOR)
#define SUNXI_DISP_VERSION_MAJOR_GET(x) (((x) >> 16) & 0x7FFF)
#define SUNXI_DISP_VERSION_MINOR_GET(x) ((x) & 0xFFFF)

typedef struct {
__u8 alpha;
__u8 red;
Expand Down Expand Up @@ -622,7 +630,7 @@ typedef struct {

typedef enum tag_DISP_CMD {
/* ----disp global---- */
DISP_CMD_RESERVE0 = 0x00,
DISP_CMD_VERSION = 0x00,
DISP_CMD_RESERVE1 = 0x01,
/* fail when the value is 0x02 in linux,why??? */
DISP_CMD_SET_BKCOLOR = 0x3f,
Expand Down

0 comments on commit 0294e5b

Please sign in to comment.