Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
 51 static 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 
 62 static 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 
 73 static 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 
 91 static 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 
103 static 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 */
119 static void hecubafb_dpy_deferred_io(struct fb_info *info,
120                                 struct list_head *pagelist)
121 {
122         hecubafb_dpy_update(info->par);
123 }
124 
125 static 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 
135 static 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 
145 static 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  */
159 static 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 
201 static 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 
210 static struct fb_deferred_io hecubafb_defio = {
211         .delay          = HZ,
212         .deferred_io    = hecubafb_dpy_deferred_io,
213 };
214 
215 static 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;
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;
276 err_fbreg:
277         framebuffer_release(info);
278 err_fballoc:
279         vfree(videomemory);
280         module_put(board->owner);
281         return retval;
282 }
283 
284 static 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 
301 static 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 
310 static int __init hecubafb_init(void)
311 {
312         return platform_driver_register(&hecubafb_driver);
313 }
314 
315 static void __exit hecubafb_exit(void)
316 {
317         platform_driver_unregister(&hecubafb_driver);
318 }
319 
320 module_init(hecubafb_init);
321 module_exit(hecubafb_exit);
322 
323 MODULE_DESCRIPTION("fbdev driver for Hecuba/Apollo controller");
324 MODULE_AUTHOR("Jaya Kumar");
325 MODULE_LICENSE("GPL");
326 
  This page was automatically generated by the LXR engine.