From: Ico Doornekamp <fbdev@zevv.nl>
To: linux-fbdev-devel@lists.sourceforge.net
Subject: Re: Questions about fbdriver integration
Date: Sun, 25 Nov 2007 12:21:50 +0100 [thread overview]
Message-ID: <20071125112150.GJ3183@pruts.nl> (raw)
In-Reply-To: <45a44e480711250312g54e7092j51e27c5e0011a2a@mail.gmail.com>
> On Nov 25, 2007 5:53 AM, Ico Doornekamp <fbdev@zevv.nl> wrote:
> >
> > I'm running 2.6.23.8 on i386. I can post the driver code if this would
> > be of any help.
> >
>
> Yes, I think it'll help. I'll try to upgrade to top of tree as well.
The driver uses on-chip GPIO for communication with the LCD, which is
handled by the v86sxgpio_* functions.
mbarcfb_dpy_update() does a complete screen update; the layout of the
LCD is different from the fbdev, so the 'transpose' function is doing
some logic to find the proper pixels. This code is still far from
optimal.
The code needs some cleanup and #defines for magic numbers here and
there, but the general idea should be clear.
write() and mmap() from userspace both work fine at this moment, I'm
still working on getting the console to display.
Ico
/*
* linux/drivers/video/mbarcfb.c -- FB driver for mbarc display
*
* Copyright (C) 2007, Ico Doornekamp
* Based on the Hecuba driver
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/v86sxgpio.h>
#define DPY_W 128
#define DPY_H 64
struct mbarcfb_par {
struct v86sxgpio *gpio_data;
struct v86sxgpio *gpio_ctrl;
int ctrl_bits;
struct fb_info *info;
};
static struct fb_fix_screeninfo mbarcfb_fix __devinitdata = {
.id = "mbarcfb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_MONO01,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo mbarcfb_var __devinitdata = {
.xres = DPY_W,
.yres = DPY_H,
.xres_virtual = DPY_W,
.yres_virtual = DPY_H,
.bits_per_pixel = 1,
.nonstd = 1,
};
static DECLARE_WAIT_QUEUE_HEAD(mbarcfb_waitq);
static struct platform_device *mbarcfb_device;
#define DI_INSTR 0
#define DI_DATA 1
#define RW_WRITE 0
#define RW_READ 1
#define BIT_DI (1<<0)
#define BIT_RW (1<<1)
#define BIT_EN (1<<2)
#define BIT_CS1 (1<<3)
#define BIT_CS2 (1<<4)
#define BIT_RST (1<<5)
static void mbarc_set(struct mbarcfb_par *par, int mask, int val)
{
if(val) {
par->ctrl_bits |= mask;
} else {
par->ctrl_bits &= ~mask;
}
v86sxgpio_set(par->gpio_ctrl, par->ctrl_bits);
}
static void mbarc_send(struct mbarcfb_par *par, int di, int val)
{
mbarc_set(par, BIT_DI, di);
mbarc_set(par, BIT_RW, RW_WRITE);
v86sxgpio_set(par->gpio_data, val);
mbarc_set(par, BIT_EN, 1);
mbarc_set(par, BIT_EN, 0);
}
static int __devinit mbarc_init_control(struct mbarcfb_par *par)
{
mbarc_set(par, BIT_RST, 0);
mbarc_set(par, BIT_RST, 1);
mbarc_send(par, DI_DATA, 0xff);
mbarc_send(par, DI_DATA, 0xff);
mbarc_send(par, DI_DATA, 0xff);
mbarc_send(par, DI_INSTR, 0xe2);
return 0;
}
u8 transpose(u8 *src, unsigned x, unsigned y)
{
u8 b;
int i;
u8 mask;
unsigned offset;
mask = 1 << ( 7 - (x%8));
b = 0;
for(i=0; i<8; i++) {
offset = (x + (y+i)*DPY_W) / 8;
if( src[offset] & mask ) b |= (1<<i);
}
return b;
}
/* main mbarcfb functions */
static void mbarcfb_dpy_update(struct mbarcfb_par *par)
{
unsigned char *buf = (unsigned char __force *)par->info->screen_base;
unsigned c, x, cx, y;
u8 *p;
u8 b;
p = buf;
for(c=0; c<2; c++) {
mbarc_set(par, BIT_CS1, c==0);
mbarc_set(par, BIT_CS2, c==1);
for(y=0; y<64; y+=8) {
mbarc_send(par, DI_INSTR, 0x40);
mbarc_send(par, DI_INSTR, 0xb8 + y/8);
mbarc_send(par, DI_INSTR, 0xc0); /* display start line */
for(cx=0; cx<64; cx++) {
x = cx + c*64;
b = transpose(buf, x, y);
mbarc_send(par, DI_DATA, b);
mbarc_send(par, DI_INSTR, 0x3f); /* wtf! */
}
}
}
for(c=0; c<2; c++) {
mbarc_set(par, BIT_CS1, c==0);
mbarc_set(par, BIT_CS2, c==1);
mbarc_send(par, DI_INSTR, 0x3f); /* wtf! */
}
}
/* this is called back from the deferred io workqueue */
static void mbarcfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagelist)
{
mbarcfb_dpy_update(info->par);
}
static void mbarcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct mbarcfb_par *par = info->par;
sys_fillrect(info, rect);
mbarcfb_dpy_update(par);
}
static void mbarcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
struct mbarcfb_par *par = info->par;
sys_copyarea(info, area);
mbarcfb_dpy_update(par);
}
static void mbarcfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct mbarcfb_par *par = info->par;
sys_imageblit(info, image);
mbarcfb_dpy_update(par);
}
/*
* this is the slow path from userspace. they can seek and write to
* the fb. it's inefficient to do anything less than a full screen draw
*/
static ssize_t mbarcfb_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p;
int err=-EINVAL;
struct mbarcfb_par *par;
unsigned int xres;
unsigned int fbmemlength;
p = *ppos;
par = info->par;
xres = info->var.xres;
fbmemlength = (xres * info->var.yres)/8;
if (p > fbmemlength)
return -ENOSPC;
err = 0;
if ((count + p) > fbmemlength) {
count = fbmemlength - p;
err = -ENOSPC;
}
if (count) {
char *base_addr;
base_addr = (char __force *)info->screen_base;
count -= copy_from_user(base_addr + p, buf, count);
*ppos += count;
err = -EFAULT;
}
mbarcfb_dpy_update(par);
if (count)
return count;
return err;
}
static struct fb_ops mbarcfb_ops = {
.owner = THIS_MODULE,
.fb_read = fb_sys_read,
.fb_write = mbarcfb_write,
.fb_fillrect = mbarcfb_fillrect,
.fb_copyarea = mbarcfb_copyarea,
.fb_imageblit = mbarcfb_imageblit,
};
static struct fb_deferred_io mbarcfb_defio = {
.delay = HZ / 5,
.deferred_io = mbarcfb_dpy_deferred_io,
};
static int __devinit mbarcfb_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
int videomemorysize;
unsigned char *videomemory;
struct mbarcfb_par *par;
videomemorysize = (DPY_W*DPY_H)/8;
if (!(videomemory = vmalloc(videomemorysize)))
return retval;
memset(videomemory, 0, videomemorysize);
info = framebuffer_alloc(sizeof(struct mbarcfb_par), &dev->dev);
if (!info)
goto err;
info->screen_base = (char __iomem *) videomemory;
info->fbops = &mbarcfb_ops;
info->var = mbarcfb_var;
info->fix = mbarcfb_fix;
info->fix.smem_len = videomemorysize;
par = info->par;
par->info = info;
par->gpio_ctrl = v86sxgpio_request("mbarcfb-ctrl", 0, 0, 6);
if(!par->gpio_ctrl) {
printk(KERN_WARNING "cant get ctrl gpio\n");
goto err1;
}
v86sxgpio_ddr(par->gpio_ctrl, 0x3f);
par->ctrl_bits = 0;
par->gpio_data = v86sxgpio_request("mbarcfb-data", 1, 0, 8);
if(!par->gpio_data) {
printk(KERN_WARNING "cant get data gpio\n");
goto err2;
}
v86sxgpio_ddr(par->gpio_data, 0xff);
info->flags = FBINFO_FLAG_DEFAULT;
info->fbdefio = &mbarcfb_defio;
fb_deferred_io_init(info);
retval = register_framebuffer(info);
if (retval < 0)
goto err3;
platform_set_drvdata(dev, info);
printk(KERN_INFO
"fb%d: Mbarc frame buffer device, using %dK of video memory\n",
info->node, videomemorysize >> 10);
/* this inits the dpy */
mbarc_init_control(par);
return 0;
err3:
v86sxgpio_release(par->gpio_data);
err2:
v86sxgpio_release(par->gpio_ctrl);
err1:
framebuffer_release(info);
err:
vfree(videomemory);
return retval;
}
static int __devexit mbarcfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
struct mbarcfb_par *par;
if (info) {
fb_deferred_io_cleanup(info);
unregister_framebuffer(info);
vfree((void __force *)info->screen_base);
framebuffer_release(info);
par = info->par;
v86sxgpio_release(par->gpio_data);
v86sxgpio_release(par->gpio_ctrl);
}
return 0;
}
static struct platform_driver mbarcfb_driver = {
.probe = mbarcfb_probe,
.remove = mbarcfb_remove,
.driver = {
.name = "mbarcfb",
},
};
static int __init mbarcfb_init(void)
{
int ret;
ret = platform_driver_register(&mbarcfb_driver);
if (!ret) {
mbarcfb_device = platform_device_alloc("mbarcfb", 0);
if (mbarcfb_device)
ret = platform_device_add(mbarcfb_device);
else
ret = -ENOMEM;
if (ret) {
platform_device_put(mbarcfb_device);
platform_driver_unregister(&mbarcfb_driver);
}
}
return ret;
}
static void __exit mbarcfb_exit(void)
{
platform_device_unregister(mbarcfb_device);
platform_driver_unregister(&mbarcfb_driver);
}
module_init(mbarcfb_init);
module_exit(mbarcfb_exit);
MODULE_DESCRIPTION("fbdev driver for Mbarc board");
MODULE_AUTHOR("Ico Doornekamp");
MODULE_LICENSE("GPL");
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
next prev parent reply other threads:[~2007-11-25 11:22 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-24 21:43 Questions about fbdriver integration Ico Doornekamp
2007-11-24 22:09 ` Ico Doornekamp
2007-11-24 22:14 ` Ico Doornekamp
2007-11-24 22:49 ` Jaya Kumar
2007-11-25 9:05 ` Ico Doornekamp
2007-11-25 10:48 ` Jaya Kumar
2007-11-25 10:53 ` Ico Doornekamp
2007-11-25 11:12 ` Jaya Kumar
2007-11-25 11:21 ` Ico Doornekamp [this message]
2007-11-28 11:40 ` Ico Doornekamp
2007-11-28 13:00 ` Jaya Kumar
2007-11-28 13:11 ` Jaya Kumar
2007-11-28 13:21 ` Ico Doornekamp
2007-11-25 8:49 ` Geert Uytterhoeven
2007-11-25 10:51 ` Ico Doornekamp
2007-11-25 12:51 ` Ico Doornekamp
2007-11-25 13:32 ` Questions about fbdriver integration (solved) Ico Doornekamp
2007-11-25 22:17 ` Geert Uytterhoeven
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20071125112150.GJ3183@pruts.nl \
--to=fbdev@zevv.nl \
--cc=linux-fbdev-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).