Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller
0003  *
0004  * Copyright (C) 2006, Jaya Kumar
0005  * This work was sponsored by CIS(M) Sdn Bhd
0006  *
0007  * This file is subject to the terms and conditions of the GNU General Public
0008  * License. See the file COPYING in the main directory of this archive for
0009  * more details.
0010  *
0011  * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
0012  * This work was possible because of apollo display code from E-Ink's website
0013  * http://support.eink.com/community
0014  * All information used to write this code is from public material made
0015  * available by E-Ink on its support site. Some commands such as 0xA4
0016  * were found by looping through cmd=0x00 thru 0xFF and supplying random
0017  * values. There are other commands that the display is capable of,
0018  * beyond the 5 used here but they are more complex.
0019  *
0020  * This driver is written to be used with the Hecuba display architecture.
0021  * The actual display chip is called Apollo and the interface electronics
0022  * it needs is called Hecuba.
0023  *
0024  * It is intended to be architecture independent. A board specific driver
0025  * must be used to perform all the physical IO interactions. An example
0026  * is provided as n411.c
0027  *
0028  */
0029 
0030 #include <linux/module.h>
0031 #include <linux/kernel.h>
0032 #include <linux/errno.h>
0033 #include <linux/string.h>
0034 #include <linux/mm.h>
0035 #include <linux/vmalloc.h>
0036 #include <linux/delay.h>
0037 #include <linux/interrupt.h>
0038 #include <linux/fb.h>
0039 #include <linux/init.h>
0040 #include <linux/platform_device.h>
0041 #include <linux/list.h>
0042 #include <linux/uaccess.h>
0043 
0044 #include <video/hecubafb.h>
0045 
0046 /* Display specific information */
0047 #define DPY_W 600
0048 #define DPY_H 800
0049 
0050 static const struct fb_fix_screeninfo hecubafb_fix = {
0051     .id =       "hecubafb",
0052     .type =     FB_TYPE_PACKED_PIXELS,
0053     .visual =   FB_VISUAL_MONO01,
0054     .xpanstep = 0,
0055     .ypanstep = 0,
0056     .ywrapstep =    0,
0057     .line_length =  DPY_W,
0058     .accel =    FB_ACCEL_NONE,
0059 };
0060 
0061 static const struct fb_var_screeninfo hecubafb_var = {
0062     .xres       = DPY_W,
0063     .yres       = DPY_H,
0064     .xres_virtual   = DPY_W,
0065     .yres_virtual   = DPY_H,
0066     .bits_per_pixel = 1,
0067     .nonstd     = 1,
0068 };
0069 
0070 /* main hecubafb functions */
0071 
0072 static void apollo_send_data(struct hecubafb_par *par, unsigned char data)
0073 {
0074     /* set data */
0075     par->board->set_data(par, data);
0076 
0077     /* set DS low */
0078     par->board->set_ctl(par, HCB_DS_BIT, 0);
0079 
0080     /* wait for ack */
0081     par->board->wait_for_ack(par, 0);
0082 
0083     /* set DS hi */
0084     par->board->set_ctl(par, HCB_DS_BIT, 1);
0085 
0086     /* wait for ack to clear */
0087     par->board->wait_for_ack(par, 1);
0088 }
0089 
0090 static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
0091 {
0092     /* command so set CD to high */
0093     par->board->set_ctl(par, HCB_CD_BIT, 1);
0094 
0095     /* actually strobe with command */
0096     apollo_send_data(par, data);
0097 
0098     /* clear CD back to low */
0099     par->board->set_ctl(par, HCB_CD_BIT, 0);
0100 }
0101 
0102 static void hecubafb_dpy_update(struct hecubafb_par *par)
0103 {
0104     int i;
0105     unsigned char *buf = (unsigned char __force *)par->info->screen_base;
0106 
0107     apollo_send_command(par, APOLLO_START_NEW_IMG);
0108 
0109     for (i=0; i < (DPY_W*DPY_H/8); i++) {
0110         apollo_send_data(par, *(buf++));
0111     }
0112 
0113     apollo_send_command(par, APOLLO_STOP_IMG_DATA);
0114     apollo_send_command(par, APOLLO_DISPLAY_IMG);
0115 }
0116 
0117 /* this is called back from the deferred io workqueue */
0118 static void hecubafb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist)
0119 {
0120     hecubafb_dpy_update(info->par);
0121 }
0122 
0123 static void hecubafb_fillrect(struct fb_info *info,
0124                    const struct fb_fillrect *rect)
0125 {
0126     struct hecubafb_par *par = info->par;
0127 
0128     sys_fillrect(info, rect);
0129 
0130     hecubafb_dpy_update(par);
0131 }
0132 
0133 static void hecubafb_copyarea(struct fb_info *info,
0134                    const struct fb_copyarea *area)
0135 {
0136     struct hecubafb_par *par = info->par;
0137 
0138     sys_copyarea(info, area);
0139 
0140     hecubafb_dpy_update(par);
0141 }
0142 
0143 static void hecubafb_imageblit(struct fb_info *info,
0144                 const struct fb_image *image)
0145 {
0146     struct hecubafb_par *par = info->par;
0147 
0148     sys_imageblit(info, image);
0149 
0150     hecubafb_dpy_update(par);
0151 }
0152 
0153 /*
0154  * this is the slow path from userspace. they can seek and write to
0155  * the fb. it's inefficient to do anything less than a full screen draw
0156  */
0157 static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
0158                 size_t count, loff_t *ppos)
0159 {
0160     struct hecubafb_par *par = info->par;
0161     unsigned long p = *ppos;
0162     void *dst;
0163     int err = 0;
0164     unsigned long total_size;
0165 
0166     if (info->state != FBINFO_STATE_RUNNING)
0167         return -EPERM;
0168 
0169     total_size = info->fix.smem_len;
0170 
0171     if (p > total_size)
0172         return -EFBIG;
0173 
0174     if (count > total_size) {
0175         err = -EFBIG;
0176         count = total_size;
0177     }
0178 
0179     if (count + p > total_size) {
0180         if (!err)
0181             err = -ENOSPC;
0182 
0183         count = total_size - p;
0184     }
0185 
0186     dst = (void __force *) (info->screen_base + p);
0187 
0188     if (copy_from_user(dst, buf, count))
0189         err = -EFAULT;
0190 
0191     if  (!err)
0192         *ppos += count;
0193 
0194     hecubafb_dpy_update(par);
0195 
0196     return (err) ? err : count;
0197 }
0198 
0199 static const struct fb_ops hecubafb_ops = {
0200     .owner      = THIS_MODULE,
0201     .fb_read        = fb_sys_read,
0202     .fb_write   = hecubafb_write,
0203     .fb_fillrect    = hecubafb_fillrect,
0204     .fb_copyarea    = hecubafb_copyarea,
0205     .fb_imageblit   = hecubafb_imageblit,
0206     .fb_mmap    = fb_deferred_io_mmap,
0207 };
0208 
0209 static struct fb_deferred_io hecubafb_defio = {
0210     .delay      = HZ,
0211     .deferred_io    = hecubafb_dpy_deferred_io,
0212 };
0213 
0214 static int hecubafb_probe(struct platform_device *dev)
0215 {
0216     struct fb_info *info;
0217     struct hecuba_board *board;
0218     int retval = -ENOMEM;
0219     int videomemorysize;
0220     unsigned char *videomemory;
0221     struct hecubafb_par *par;
0222 
0223     /* pick up board specific routines */
0224     board = dev->dev.platform_data;
0225     if (!board)
0226         return -EINVAL;
0227 
0228     /* try to count device specific driver, if can't, platform recalls */
0229     if (!try_module_get(board->owner))
0230         return -ENODEV;
0231 
0232     videomemorysize = (DPY_W*DPY_H)/8;
0233 
0234     videomemory = vzalloc(videomemorysize);
0235     if (!videomemory)
0236         goto err_videomem_alloc;
0237 
0238     info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
0239     if (!info)
0240         goto err_fballoc;
0241 
0242     info->screen_base = (char __force __iomem *)videomemory;
0243     info->fbops = &hecubafb_ops;
0244 
0245     info->var = hecubafb_var;
0246     info->fix = hecubafb_fix;
0247     info->fix.smem_len = videomemorysize;
0248     par = info->par;
0249     par->info = info;
0250     par->board = board;
0251     par->send_command = apollo_send_command;
0252     par->send_data = apollo_send_data;
0253 
0254     info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
0255 
0256     info->fbdefio = &hecubafb_defio;
0257     fb_deferred_io_init(info);
0258 
0259     retval = register_framebuffer(info);
0260     if (retval < 0)
0261         goto err_fbreg;
0262     platform_set_drvdata(dev, info);
0263 
0264     fb_info(info, "Hecuba frame buffer device, using %dK of video memory\n",
0265         videomemorysize >> 10);
0266 
0267     /* this inits the dpy */
0268     retval = par->board->init(par);
0269     if (retval < 0)
0270         goto err_fbreg;
0271 
0272     return 0;
0273 err_fbreg:
0274     framebuffer_release(info);
0275 err_fballoc:
0276     vfree(videomemory);
0277 err_videomem_alloc:
0278     module_put(board->owner);
0279     return retval;
0280 }
0281 
0282 static int hecubafb_remove(struct platform_device *dev)
0283 {
0284     struct fb_info *info = platform_get_drvdata(dev);
0285 
0286     if (info) {
0287         struct hecubafb_par *par = info->par;
0288         fb_deferred_io_cleanup(info);
0289         unregister_framebuffer(info);
0290         vfree((void __force *)info->screen_base);
0291         if (par->board->remove)
0292             par->board->remove(par);
0293         module_put(par->board->owner);
0294         framebuffer_release(info);
0295     }
0296     return 0;
0297 }
0298 
0299 static struct platform_driver hecubafb_driver = {
0300     .probe  = hecubafb_probe,
0301     .remove = hecubafb_remove,
0302     .driver = {
0303         .name   = "hecubafb",
0304     },
0305 };
0306 module_platform_driver(hecubafb_driver);
0307 
0308 MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller");
0309 MODULE_AUTHOR("Jaya Kumar");
0310 MODULE_LICENSE("GPL");