Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.34-rc3 325 lines 7.7 kB view raw
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/slab.h> 36#include <linux/vmalloc.h> 37#include <linux/delay.h> 38#include <linux/interrupt.h> 39#include <linux/fb.h> 40#include <linux/init.h> 41#include <linux/platform_device.h> 42#include <linux/list.h> 43#include <linux/uaccess.h> 44 45#include <video/hecubafb.h> 46 47/* Display specific information */ 48#define DPY_W 600 49#define DPY_H 800 50 51static struct fb_fix_screeninfo hecubafb_fix __devinitdata = { 52 .id = "hecubafb", 53 .type = FB_TYPE_PACKED_PIXELS, 54 .visual = FB_VISUAL_MONO01, 55 .xpanstep = 0, 56 .ypanstep = 0, 57 .ywrapstep = 0, 58 .line_length = DPY_W, 59 .accel = FB_ACCEL_NONE, 60}; 61 62static struct fb_var_screeninfo hecubafb_var __devinitdata = { 63 .xres = DPY_W, 64 .yres = DPY_H, 65 .xres_virtual = DPY_W, 66 .yres_virtual = DPY_H, 67 .bits_per_pixel = 1, 68 .nonstd = 1, 69}; 70 71/* main hecubafb functions */ 72 73static void apollo_send_data(struct hecubafb_par *par, unsigned char data) 74{ 75 /* set data */ 76 par->board->set_data(par, data); 77 78 /* set DS low */ 79 par->board->set_ctl(par, HCB_DS_BIT, 0); 80 81 /* wait for ack */ 82 par->board->wait_for_ack(par, 0); 83 84 /* set DS hi */ 85 par->board->set_ctl(par, HCB_DS_BIT, 1); 86 87 /* wait for ack to clear */ 88 par->board->wait_for_ack(par, 1); 89} 90 91static void apollo_send_command(struct hecubafb_par *par, unsigned char data) 92{ 93 /* command so set CD to high */ 94 par->board->set_ctl(par, HCB_CD_BIT, 1); 95 96 /* actually strobe with command */ 97 apollo_send_data(par, data); 98 99 /* clear CD back to low */ 100 par->board->set_ctl(par, HCB_CD_BIT, 0); 101} 102 103static void hecubafb_dpy_update(struct hecubafb_par *par) 104{ 105 int i; 106 unsigned char *buf = (unsigned char __force *)par->info->screen_base; 107 108 apollo_send_command(par, APOLLO_START_NEW_IMG); 109 110 for (i=0; i < (DPY_W*DPY_H/8); i++) { 111 apollo_send_data(par, *(buf++)); 112 } 113 114 apollo_send_command(par, APOLLO_STOP_IMG_DATA); 115 apollo_send_command(par, APOLLO_DISPLAY_IMG); 116} 117 118/* this is called back from the deferred io workqueue */ 119static void hecubafb_dpy_deferred_io(struct fb_info *info, 120 struct list_head *pagelist) 121{ 122 hecubafb_dpy_update(info->par); 123} 124 125static void hecubafb_fillrect(struct fb_info *info, 126 const struct fb_fillrect *rect) 127{ 128 struct hecubafb_par *par = info->par; 129 130 sys_fillrect(info, rect); 131 132 hecubafb_dpy_update(par); 133} 134 135static void hecubafb_copyarea(struct fb_info *info, 136 const struct fb_copyarea *area) 137{ 138 struct hecubafb_par *par = info->par; 139 140 sys_copyarea(info, area); 141 142 hecubafb_dpy_update(par); 143} 144 145static void hecubafb_imageblit(struct fb_info *info, 146 const struct fb_image *image) 147{ 148 struct hecubafb_par *par = info->par; 149 150 sys_imageblit(info, image); 151 152 hecubafb_dpy_update(par); 153} 154 155/* 156 * this is the slow path from userspace. they can seek and write to 157 * the fb. it's inefficient to do anything less than a full screen draw 158 */ 159static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf, 160 size_t count, loff_t *ppos) 161{ 162 struct hecubafb_par *par = info->par; 163 unsigned long p = *ppos; 164 void *dst; 165 int err = 0; 166 unsigned long total_size; 167 168 if (info->state != FBINFO_STATE_RUNNING) 169 return -EPERM; 170 171 total_size = info->fix.smem_len; 172 173 if (p > total_size) 174 return -EFBIG; 175 176 if (count > total_size) { 177 err = -EFBIG; 178 count = total_size; 179 } 180 181 if (count + p > total_size) { 182 if (!err) 183 err = -ENOSPC; 184 185 count = total_size - p; 186 } 187 188 dst = (void __force *) (info->screen_base + p); 189 190 if (copy_from_user(dst, buf, count)) 191 err = -EFAULT; 192 193 if (!err) 194 *ppos += count; 195 196 hecubafb_dpy_update(par); 197 198 return (err) ? err : count; 199} 200 201static struct fb_ops hecubafb_ops = { 202 .owner = THIS_MODULE, 203 .fb_read = fb_sys_read, 204 .fb_write = hecubafb_write, 205 .fb_fillrect = hecubafb_fillrect, 206 .fb_copyarea = hecubafb_copyarea, 207 .fb_imageblit = hecubafb_imageblit, 208}; 209 210static struct fb_deferred_io hecubafb_defio = { 211 .delay = HZ, 212 .deferred_io = hecubafb_dpy_deferred_io, 213}; 214 215static int __devinit hecubafb_probe(struct platform_device *dev) 216{ 217 struct fb_info *info; 218 struct hecuba_board *board; 219 int retval = -ENOMEM; 220 int videomemorysize; 221 unsigned char *videomemory; 222 struct hecubafb_par *par; 223 224 /* pick up board specific routines */ 225 board = dev->dev.platform_data; 226 if (!board) 227 return -EINVAL; 228 229 /* try to count device specific driver, if can't, platform recalls */ 230 if (!try_module_get(board->owner)) 231 return -ENODEV; 232 233 videomemorysize = (DPY_W*DPY_H)/8; 234 235 if (!(videomemory = vmalloc(videomemorysize))) 236 return retval; 237 238 memset(videomemory, 0, videomemorysize); 239 240 info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev); 241 if (!info) 242 goto err_fballoc; 243 244 info->screen_base = (char __force __iomem *)videomemory; 245 info->fbops = &hecubafb_ops; 246 247 info->var = hecubafb_var; 248 info->fix = hecubafb_fix; 249 info->fix.smem_len = videomemorysize; 250 par = info->par; 251 par->info = info; 252 par->board = board; 253 par->send_command = apollo_send_command; 254 par->send_data = apollo_send_data; 255 256 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; 257 258 info->fbdefio = &hecubafb_defio; 259 fb_deferred_io_init(info); 260 261 retval = register_framebuffer(info); 262 if (retval < 0) 263 goto err_fbreg; 264 platform_set_drvdata(dev, info); 265 266 printk(KERN_INFO 267 "fb%d: Hecuba frame buffer device, using %dK of video memory\n", 268 info->node, videomemorysize >> 10); 269 270 /* this inits the dpy */ 271 retval = par->board->init(par); 272 if (retval < 0) 273 goto err_fbreg; 274 275 return 0; 276err_fbreg: 277 framebuffer_release(info); 278err_fballoc: 279 vfree(videomemory); 280 module_put(board->owner); 281 return retval; 282} 283 284static int __devexit hecubafb_remove(struct platform_device *dev) 285{ 286 struct fb_info *info = platform_get_drvdata(dev); 287 288 if (info) { 289 struct hecubafb_par *par = info->par; 290 fb_deferred_io_cleanup(info); 291 unregister_framebuffer(info); 292 vfree((void __force *)info->screen_base); 293 if (par->board->remove) 294 par->board->remove(par); 295 module_put(par->board->owner); 296 framebuffer_release(info); 297 } 298 return 0; 299} 300 301static struct platform_driver hecubafb_driver = { 302 .probe = hecubafb_probe, 303 .remove = hecubafb_remove, 304 .driver = { 305 .owner = THIS_MODULE, 306 .name = "hecubafb", 307 }, 308}; 309 310static int __init hecubafb_init(void) 311{ 312 return platform_driver_register(&hecubafb_driver); 313} 314 315static void __exit hecubafb_exit(void) 316{ 317 platform_driver_unregister(&hecubafb_driver); 318} 319 320module_init(hecubafb_init); 321module_exit(hecubafb_exit); 322 323MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller"); 324MODULE_AUTHOR("Jaya Kumar"); 325MODULE_LICENSE("GPL");