root/drivers/video/fbdev/hecubafb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. apollo_send_data
  2. apollo_send_command
  3. hecubafb_dpy_update
  4. hecubafb_dpy_deferred_io
  5. hecubafb_fillrect
  6. hecubafb_copyarea
  7. hecubafb_imageblit
  8. hecubafb_write
  9. hecubafb_probe
  10. hecubafb_remove

   1 /*
   2  * linux/drivers/video/hecubafb.c -- FB driver for Hecuba/Apollo controller
   3  *
   4  * Copyright (C) 2006, Jaya Kumar
   5  * This work was sponsored by CIS(M) Sdn Bhd
   6  *
   7  * This file is subject to the terms and conditions of the GNU General Public
   8  * License. See the file COPYING in the main directory of this archive for
   9  * more details.
  10  *
  11  * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
  12  * This work was possible because of apollo display code from E-Ink's website
  13  * http://support.eink.com/community
  14  * All information used to write this code is from public material made
  15  * available by E-Ink on its support site. Some commands such as 0xA4
  16  * were found by looping through cmd=0x00 thru 0xFF and supplying random
  17  * values. There are other commands that the display is capable of,
  18  * beyond the 5 used here but they are more complex.
  19  *
  20  * This driver is written to be used with the Hecuba display architecture.
  21  * The actual display chip is called Apollo and the interface electronics
  22  * it needs is called Hecuba.
  23  *
  24  * It is intended to be architecture independent. A board specific driver
  25  * must be used to perform all the physical IO interactions. An example
  26  * is provided as n411.c
  27  *
  28  */
  29 
  30 #include <linux/module.h>
  31 #include <linux/kernel.h>
  32 #include <linux/errno.h>
  33 #include <linux/string.h>
  34 #include <linux/mm.h>
  35 #include <linux/vmalloc.h>
  36 #include <linux/delay.h>
  37 #include <linux/interrupt.h>
  38 #include <linux/fb.h>
  39 #include <linux/init.h>
  40 #include <linux/platform_device.h>
  41 #include <linux/list.h>
  42 #include <linux/uaccess.h>
  43 
  44 #include <video/hecubafb.h>
  45 
  46 /* Display specific information */
  47 #define DPY_W 600
  48 #define DPY_H 800
  49 
  50 static const struct fb_fix_screeninfo hecubafb_fix = {
  51         .id =           "hecubafb",
  52         .type =         FB_TYPE_PACKED_PIXELS,
  53         .visual =       FB_VISUAL_MONO01,
  54         .xpanstep =     0,
  55         .ypanstep =     0,
  56         .ywrapstep =    0,
  57         .line_length =  DPY_W,
  58         .accel =        FB_ACCEL_NONE,
  59 };
  60 
  61 static const struct fb_var_screeninfo hecubafb_var = {
  62         .xres           = DPY_W,
  63         .yres           = DPY_H,
  64         .xres_virtual   = DPY_W,
  65         .yres_virtual   = DPY_H,
  66         .bits_per_pixel = 1,
  67         .nonstd         = 1,
  68 };
  69 
  70 /* main hecubafb functions */
  71 
  72 static void apollo_send_data(struct hecubafb_par *par, unsigned char data)
  73 {
  74         /* set data */
  75         par->board->set_data(par, data);
  76 
  77         /* set DS low */
  78         par->board->set_ctl(par, HCB_DS_BIT, 0);
  79 
  80         /* wait for ack */
  81         par->board->wait_for_ack(par, 0);
  82 
  83         /* set DS hi */
  84         par->board->set_ctl(par, HCB_DS_BIT, 1);
  85 
  86         /* wait for ack to clear */
  87         par->board->wait_for_ack(par, 1);
  88 }
  89 
  90 static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
  91 {
  92         /* command so set CD to high */
  93         par->board->set_ctl(par, HCB_CD_BIT, 1);
  94 
  95         /* actually strobe with command */
  96         apollo_send_data(par, data);
  97 
  98         /* clear CD back to low */
  99         par->board->set_ctl(par, HCB_CD_BIT, 0);
 100 }
 101 
 102 static void hecubafb_dpy_update(struct hecubafb_par *par)
 103 {
 104         int i;
 105         unsigned char *buf = (unsigned char __force *)par->info->screen_base;
 106 
 107         apollo_send_command(par, APOLLO_START_NEW_IMG);
 108 
 109         for (i=0; i < (DPY_W*DPY_H/8); i++) {
 110                 apollo_send_data(par, *(buf++));
 111         }
 112 
 113         apollo_send_command(par, APOLLO_STOP_IMG_DATA);
 114         apollo_send_command(par, APOLLO_DISPLAY_IMG);
 115 }
 116 
 117 /* this is called back from the deferred io workqueue */
 118 static void hecubafb_dpy_deferred_io(struct fb_info *info,
 119                                 struct list_head *pagelist)
 120 {
 121         hecubafb_dpy_update(info->par);
 122 }
 123 
 124 static void hecubafb_fillrect(struct fb_info *info,
 125                                    const struct fb_fillrect *rect)
 126 {
 127         struct hecubafb_par *par = info->par;
 128 
 129         sys_fillrect(info, rect);
 130 
 131         hecubafb_dpy_update(par);
 132 }
 133 
 134 static void hecubafb_copyarea(struct fb_info *info,
 135                                    const struct fb_copyarea *area)
 136 {
 137         struct hecubafb_par *par = info->par;
 138 
 139         sys_copyarea(info, area);
 140 
 141         hecubafb_dpy_update(par);
 142 }
 143 
 144 static void hecubafb_imageblit(struct fb_info *info,
 145                                 const struct fb_image *image)
 146 {
 147         struct hecubafb_par *par = info->par;
 148 
 149         sys_imageblit(info, image);
 150 
 151         hecubafb_dpy_update(par);
 152 }
 153 
 154 /*
 155  * this is the slow path from userspace. they can seek and write to
 156  * the fb. it's inefficient to do anything less than a full screen draw
 157  */
 158 static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
 159                                 size_t count, loff_t *ppos)
 160 {
 161         struct hecubafb_par *par = info->par;
 162         unsigned long p = *ppos;
 163         void *dst;
 164         int err = 0;
 165         unsigned long total_size;
 166 
 167         if (info->state != FBINFO_STATE_RUNNING)
 168                 return -EPERM;
 169 
 170         total_size = info->fix.smem_len;
 171 
 172         if (p > total_size)
 173                 return -EFBIG;
 174 
 175         if (count > total_size) {
 176                 err = -EFBIG;
 177                 count = total_size;
 178         }
 179 
 180         if (count + p > total_size) {
 181                 if (!err)
 182                         err = -ENOSPC;
 183 
 184                 count = total_size - p;
 185         }
 186 
 187         dst = (void __force *) (info->screen_base + p);
 188 
 189         if (copy_from_user(dst, buf, count))
 190                 err = -EFAULT;
 191 
 192         if  (!err)
 193                 *ppos += count;
 194 
 195         hecubafb_dpy_update(par);
 196 
 197         return (err) ? err : count;
 198 }
 199 
 200 static struct fb_ops hecubafb_ops = {
 201         .owner          = THIS_MODULE,
 202         .fb_read        = fb_sys_read,
 203         .fb_write       = hecubafb_write,
 204         .fb_fillrect    = hecubafb_fillrect,
 205         .fb_copyarea    = hecubafb_copyarea,
 206         .fb_imageblit   = hecubafb_imageblit,
 207 };
 208 
 209 static struct fb_deferred_io hecubafb_defio = {
 210         .delay          = HZ,
 211         .deferred_io    = hecubafb_dpy_deferred_io,
 212 };
 213 
 214 static int hecubafb_probe(struct platform_device *dev)
 215 {
 216         struct fb_info *info;
 217         struct hecuba_board *board;
 218         int retval = -ENOMEM;
 219         int videomemorysize;
 220         unsigned char *videomemory;
 221         struct hecubafb_par *par;
 222 
 223         /* pick up board specific routines */
 224         board = dev->dev.platform_data;
 225         if (!board)
 226                 return -EINVAL;
 227 
 228         /* try to count device specific driver, if can't, platform recalls */
 229         if (!try_module_get(board->owner))
 230                 return -ENODEV;
 231 
 232         videomemorysize = (DPY_W*DPY_H)/8;
 233 
 234         videomemory = vzalloc(videomemorysize);
 235         if (!videomemory)
 236                 goto err_videomem_alloc;
 237 
 238         info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
 239         if (!info)
 240                 goto err_fballoc;
 241 
 242         info->screen_base = (char __force __iomem *)videomemory;
 243         info->fbops = &hecubafb_ops;
 244 
 245         info->var = hecubafb_var;
 246         info->fix = hecubafb_fix;
 247         info->fix.smem_len = videomemorysize;
 248         par = info->par;
 249         par->info = info;
 250         par->board = board;
 251         par->send_command = apollo_send_command;
 252         par->send_data = apollo_send_data;
 253 
 254         info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
 255 
 256         info->fbdefio = &hecubafb_defio;
 257         fb_deferred_io_init(info);
 258 
 259         retval = register_framebuffer(info);
 260         if (retval < 0)
 261                 goto err_fbreg;
 262         platform_set_drvdata(dev, info);
 263 
 264         fb_info(info, "Hecuba frame buffer device, using %dK of video memory\n",
 265                 videomemorysize >> 10);
 266 
 267         /* this inits the dpy */
 268         retval = par->board->init(par);
 269         if (retval < 0)
 270                 goto err_fbreg;
 271 
 272         return 0;
 273 err_fbreg:
 274         framebuffer_release(info);
 275 err_fballoc:
 276         vfree(videomemory);
 277 err_videomem_alloc:
 278         module_put(board->owner);
 279         return retval;
 280 }
 281 
 282 static int hecubafb_remove(struct platform_device *dev)
 283 {
 284         struct fb_info *info = platform_get_drvdata(dev);
 285 
 286         if (info) {
 287                 struct hecubafb_par *par = info->par;
 288                 fb_deferred_io_cleanup(info);
 289                 unregister_framebuffer(info);
 290                 vfree((void __force *)info->screen_base);
 291                 if (par->board->remove)
 292                         par->board->remove(par);
 293                 module_put(par->board->owner);
 294                 framebuffer_release(info);
 295         }
 296         return 0;
 297 }
 298 
 299 static struct platform_driver hecubafb_driver = {
 300         .probe  = hecubafb_probe,
 301         .remove = hecubafb_remove,
 302         .driver = {
 303                 .name   = "hecubafb",
 304         },
 305 };
 306 module_platform_driver(hecubafb_driver);
 307 
 308 MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller");
 309 MODULE_AUTHOR("Jaya Kumar");
 310 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */