root/drivers/video/fbdev/metronomefb.c

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

DEFINITIONS

This source file includes following definitions.
  1. calc_cksum
  2. calc_img_cksum
  3. load_waveform
  4. metronome_display_cmd
  5. metronome_powerup_cmd
  6. metronome_config_cmd
  7. metronome_init_cmd
  8. metronome_init_regs
  9. metronomefb_dpy_update
  10. metronomefb_dpy_update_page
  11. metronomefb_dpy_deferred_io
  12. metronomefb_fillrect
  13. metronomefb_copyarea
  14. metronomefb_imageblit
  15. metronomefb_write
  16. metronomefb_probe
  17. metronomefb_remove

   1 /*
   2  * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller
   3  *
   4  * Copyright (C) 2008, Jaya Kumar
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License. See the file COPYING in the main directory of this archive for
   8  * more details.
   9  *
  10  * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
  11  *
  12  * This work was made possible by help and equipment support from E-Ink
  13  * Corporation. http://www.eink.com/
  14  *
  15  * This driver is written to be used with the Metronome display controller.
  16  * It is intended to be architecture independent. A board specific driver
  17  * must be used to perform all the physical IO interactions. An example
  18  * is provided as am200epd.c
  19  *
  20  */
  21 #include <linux/module.h>
  22 #include <linux/kernel.h>
  23 #include <linux/errno.h>
  24 #include <linux/string.h>
  25 #include <linux/mm.h>
  26 #include <linux/vmalloc.h>
  27 #include <linux/delay.h>
  28 #include <linux/interrupt.h>
  29 #include <linux/fb.h>
  30 #include <linux/init.h>
  31 #include <linux/platform_device.h>
  32 #include <linux/list.h>
  33 #include <linux/firmware.h>
  34 #include <linux/dma-mapping.h>
  35 #include <linux/uaccess.h>
  36 #include <linux/irq.h>
  37 
  38 #include <video/metronomefb.h>
  39 
  40 #include <asm/unaligned.h>
  41 
  42 /* Display specific information */
  43 #define DPY_W 832
  44 #define DPY_H 622
  45 
  46 static int user_wfm_size;
  47 
  48 /* frame differs from image. frame includes non-visible pixels */
  49 struct epd_frame {
  50         int fw; /* frame width */
  51         int fh; /* frame height */
  52         u16 config[4];
  53         int wfm_size;
  54 };
  55 
  56 static struct epd_frame epd_frame_table[] = {
  57         {
  58                 .fw = 832,
  59                 .fh = 622,
  60                 .config = {
  61                         15 /* sdlew */
  62                         | 2 << 8 /* sdosz */
  63                         | 0 << 11 /* sdor */
  64                         | 0 << 12 /* sdces */
  65                         | 0 << 15, /* sdcer */
  66                         42 /* gdspl */
  67                         | 1 << 8 /* gdr1 */
  68                         | 1 << 9 /* sdshr */
  69                         | 0 << 15, /* gdspp */
  70                         18 /* gdspw */
  71                         | 0 << 15, /* dispc */
  72                         599 /* vdlc */
  73                         | 0 << 11 /* dsi */
  74                         | 0 << 12, /* dsic */
  75                 },
  76                 .wfm_size = 47001,
  77         },
  78         {
  79                 .fw = 1088,
  80                 .fh = 791,
  81                 .config = {
  82                         0x0104,
  83                         0x031f,
  84                         0x0088,
  85                         0x02ff,
  86                 },
  87                 .wfm_size = 46770,
  88         },
  89         {
  90                 .fw = 1200,
  91                 .fh = 842,
  92                 .config = {
  93                         0x0101,
  94                         0x030e,
  95                         0x0012,
  96                         0x0280,
  97                 },
  98                 .wfm_size = 46770,
  99         },
 100 };
 101 
 102 static struct fb_fix_screeninfo metronomefb_fix = {
 103         .id =           "metronomefb",
 104         .type =         FB_TYPE_PACKED_PIXELS,
 105         .visual =       FB_VISUAL_STATIC_PSEUDOCOLOR,
 106         .xpanstep =     0,
 107         .ypanstep =     0,
 108         .ywrapstep =    0,
 109         .line_length =  DPY_W,
 110         .accel =        FB_ACCEL_NONE,
 111 };
 112 
 113 static struct fb_var_screeninfo metronomefb_var = {
 114         .xres           = DPY_W,
 115         .yres           = DPY_H,
 116         .xres_virtual   = DPY_W,
 117         .yres_virtual   = DPY_H,
 118         .bits_per_pixel = 8,
 119         .grayscale      = 1,
 120         .nonstd         = 1,
 121         .red =          { 4, 3, 0 },
 122         .green =        { 0, 0, 0 },
 123         .blue =         { 0, 0, 0 },
 124         .transp =       { 0, 0, 0 },
 125 };
 126 
 127 /* the waveform structure that is coming from userspace firmware */
 128 struct waveform_hdr {
 129         u8 stuff[32];
 130 
 131         u8 wmta[3];
 132         u8 fvsn;
 133 
 134         u8 luts;
 135         u8 mc;
 136         u8 trc;
 137         u8 stuff3;
 138 
 139         u8 endb;
 140         u8 swtb;
 141         u8 stuff2a[2];
 142 
 143         u8 stuff2b[3];
 144         u8 wfm_cs;
 145 } __attribute__ ((packed));
 146 
 147 /* main metronomefb functions */
 148 static u8 calc_cksum(int start, int end, u8 *mem)
 149 {
 150         u8 tmp = 0;
 151         int i;
 152 
 153         for (i = start; i < end; i++)
 154                 tmp += mem[i];
 155 
 156         return tmp;
 157 }
 158 
 159 static u16 calc_img_cksum(u16 *start, int length)
 160 {
 161         u16 tmp = 0;
 162 
 163         while (length--)
 164                 tmp += *start++;
 165 
 166         return tmp;
 167 }
 168 
 169 /* here we decode the incoming waveform file and populate metromem */
 170 static int load_waveform(u8 *mem, size_t size, int m, int t,
 171                          struct metronomefb_par *par)
 172 {
 173         int tta;
 174         int wmta;
 175         int trn = 0;
 176         int i;
 177         unsigned char v;
 178         u8 cksum;
 179         int cksum_idx;
 180         int wfm_idx, owfm_idx;
 181         int mem_idx = 0;
 182         struct waveform_hdr *wfm_hdr;
 183         u8 *metromem = par->metromem_wfm;
 184         struct device *dev = par->info->dev;
 185 
 186         if (user_wfm_size)
 187                 epd_frame_table[par->dt].wfm_size = user_wfm_size;
 188 
 189         if (size != epd_frame_table[par->dt].wfm_size) {
 190                 dev_err(dev, "Error: unexpected size %zd != %d\n", size,
 191                                         epd_frame_table[par->dt].wfm_size);
 192                 return -EINVAL;
 193         }
 194 
 195         wfm_hdr = (struct waveform_hdr *) mem;
 196 
 197         if (wfm_hdr->fvsn != 1) {
 198                 dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn);
 199                 return -EINVAL;
 200         }
 201         if (wfm_hdr->luts != 0) {
 202                 dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
 203                 return -EINVAL;
 204         }
 205         cksum = calc_cksum(32, 47, mem);
 206         if (cksum != wfm_hdr->wfm_cs) {
 207                 dev_err(dev, "Error: bad cksum %x != %x\n", cksum,
 208                                         wfm_hdr->wfm_cs);
 209                 return -EINVAL;
 210         }
 211         wfm_hdr->mc += 1;
 212         wfm_hdr->trc += 1;
 213         for (i = 0; i < 5; i++) {
 214                 if (*(wfm_hdr->stuff2a + i) != 0) {
 215                         dev_err(dev, "Error: unexpected value in padding\n");
 216                         return -EINVAL;
 217                 }
 218         }
 219 
 220         /* calculating trn. trn is something used to index into
 221         the waveform. presumably selecting the right one for the
 222         desired temperature. it works out the offset of the first
 223         v that exceeds the specified temperature */
 224         if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size)
 225                 return -EINVAL;
 226 
 227         for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
 228                 if (mem[i] > t) {
 229                         trn = i - sizeof(*wfm_hdr) - 1;
 230                         break;
 231                 }
 232         }
 233 
 234         /* check temperature range table checksum */
 235         cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
 236         if (cksum_idx >= size)
 237                 return -EINVAL;
 238         cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
 239         if (cksum != mem[cksum_idx]) {
 240                 dev_err(dev, "Error: bad temperature range table cksum"
 241                                 " %x != %x\n", cksum, mem[cksum_idx]);
 242                 return -EINVAL;
 243         }
 244 
 245         /* check waveform mode table address checksum */
 246         wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
 247         cksum_idx = wmta + m*4 + 3;
 248         if (cksum_idx >= size)
 249                 return -EINVAL;
 250         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 251         if (cksum != mem[cksum_idx]) {
 252                 dev_err(dev, "Error: bad mode table address cksum"
 253                                 " %x != %x\n", cksum, mem[cksum_idx]);
 254                 return -EINVAL;
 255         }
 256 
 257         /* check waveform temperature table address checksum */
 258         tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
 259         cksum_idx = tta + trn*4 + 3;
 260         if (cksum_idx >= size)
 261                 return -EINVAL;
 262         cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
 263         if (cksum != mem[cksum_idx]) {
 264                 dev_err(dev, "Error: bad temperature table address cksum"
 265                         " %x != %x\n", cksum, mem[cksum_idx]);
 266                 return -EINVAL;
 267         }
 268 
 269         /* here we do the real work of putting the waveform into the
 270         metromem buffer. this does runlength decoding of the waveform */
 271         wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
 272         owfm_idx = wfm_idx;
 273         if (wfm_idx >= size)
 274                 return -EINVAL;
 275         while (wfm_idx < size) {
 276                 unsigned char rl;
 277                 v = mem[wfm_idx++];
 278                 if (v == wfm_hdr->swtb) {
 279                         while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
 280                                 wfm_idx < size)
 281                                 metromem[mem_idx++] = v;
 282 
 283                         continue;
 284                 }
 285 
 286                 if (v == wfm_hdr->endb)
 287                         break;
 288 
 289                 rl = mem[wfm_idx++];
 290                 for (i = 0; i <= rl; i++)
 291                         metromem[mem_idx++] = v;
 292         }
 293 
 294         cksum_idx = wfm_idx;
 295         if (cksum_idx >= size)
 296                 return -EINVAL;
 297         cksum = calc_cksum(owfm_idx, cksum_idx, mem);
 298         if (cksum != mem[cksum_idx]) {
 299                 dev_err(dev, "Error: bad waveform data cksum"
 300                                 " %x != %x\n", cksum, mem[cksum_idx]);
 301                 return -EINVAL;
 302         }
 303         par->frame_count = (mem_idx/64);
 304 
 305         return 0;
 306 }
 307 
 308 static int metronome_display_cmd(struct metronomefb_par *par)
 309 {
 310         int i;
 311         u16 cs;
 312         u16 opcode;
 313         static u8 borderval;
 314 
 315         /* setup display command
 316         we can't immediately set the opcode since the controller
 317         will try parse the command before we've set it all up
 318         so we just set cs here and set the opcode at the end */
 319 
 320         if (par->metromem_cmd->opcode == 0xCC40)
 321                 opcode = cs = 0xCC41;
 322         else
 323                 opcode = cs = 0xCC40;
 324 
 325         /* set the args ( 2 bytes ) for display */
 326         i = 0;
 327         par->metromem_cmd->args[i] =    1 << 3 /* border update */
 328                                         | ((borderval++ % 4) & 0x0F) << 4
 329                                         | (par->frame_count - 1) << 8;
 330         cs += par->metromem_cmd->args[i++];
 331 
 332         /* the rest are 0 */
 333         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
 334 
 335         par->metromem_cmd->csum = cs;
 336         par->metromem_cmd->opcode = opcode; /* display cmd */
 337 
 338         return par->board->met_wait_event_intr(par);
 339 }
 340 
 341 static int metronome_powerup_cmd(struct metronomefb_par *par)
 342 {
 343         int i;
 344         u16 cs;
 345 
 346         /* setup power up command */
 347         par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
 348         cs = par->metromem_cmd->opcode;
 349 
 350         /* set pwr1,2,3 to 1024 */
 351         for (i = 0; i < 3; i++) {
 352                 par->metromem_cmd->args[i] = 1024;
 353                 cs += par->metromem_cmd->args[i];
 354         }
 355 
 356         /* the rest are 0 */
 357         memset(&par->metromem_cmd->args[i], 0,
 358                (ARRAY_SIZE(par->metromem_cmd->args) - i) * 2);
 359 
 360         par->metromem_cmd->csum = cs;
 361 
 362         msleep(1);
 363         par->board->set_rst(par, 1);
 364 
 365         msleep(1);
 366         par->board->set_stdby(par, 1);
 367 
 368         return par->board->met_wait_event(par);
 369 }
 370 
 371 static int metronome_config_cmd(struct metronomefb_par *par)
 372 {
 373         /* setup config command
 374         we can't immediately set the opcode since the controller
 375         will try parse the command before we've set it all up */
 376 
 377         memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
 378                 sizeof(epd_frame_table[par->dt].config));
 379         /* the rest are 0 */
 380         memset(&par->metromem_cmd->args[4], 0,
 381                (ARRAY_SIZE(par->metromem_cmd->args) - 4) * 2);
 382 
 383         par->metromem_cmd->csum = 0xCC10;
 384         par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
 385         par->metromem_cmd->opcode = 0xCC10; /* config cmd */
 386 
 387         return par->board->met_wait_event(par);
 388 }
 389 
 390 static int metronome_init_cmd(struct metronomefb_par *par)
 391 {
 392         int i;
 393         u16 cs;
 394 
 395         /* setup init command
 396         we can't immediately set the opcode since the controller
 397         will try parse the command before we've set it all up
 398         so we just set cs here and set the opcode at the end */
 399 
 400         cs = 0xCC20;
 401 
 402         /* set the args ( 2 bytes ) for init */
 403         i = 0;
 404         par->metromem_cmd->args[i] = 0;
 405         cs += par->metromem_cmd->args[i++];
 406 
 407         /* the rest are 0 */
 408         memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
 409 
 410         par->metromem_cmd->csum = cs;
 411         par->metromem_cmd->opcode = 0xCC20; /* init cmd */
 412 
 413         return par->board->met_wait_event(par);
 414 }
 415 
 416 static int metronome_init_regs(struct metronomefb_par *par)
 417 {
 418         int res;
 419 
 420         res = par->board->setup_io(par);
 421         if (res)
 422                 return res;
 423 
 424         res = metronome_powerup_cmd(par);
 425         if (res)
 426                 return res;
 427 
 428         res = metronome_config_cmd(par);
 429         if (res)
 430                 return res;
 431 
 432         res = metronome_init_cmd(par);
 433 
 434         return res;
 435 }
 436 
 437 static void metronomefb_dpy_update(struct metronomefb_par *par)
 438 {
 439         int fbsize;
 440         u16 cksum;
 441         unsigned char *buf = (unsigned char __force *)par->info->screen_base;
 442 
 443         fbsize = par->info->fix.smem_len;
 444         /* copy from vm to metromem */
 445         memcpy(par->metromem_img, buf, fbsize);
 446 
 447         cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
 448         *((u16 *)(par->metromem_img) + fbsize/2) = cksum;
 449         metronome_display_cmd(par);
 450 }
 451 
 452 static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
 453 {
 454         int i;
 455         u16 csum = 0;
 456         u16 *buf = (u16 __force *)(par->info->screen_base + index);
 457         u16 *img = (u16 *)(par->metromem_img + index);
 458 
 459         /* swizzle from vm to metromem and recalc cksum at the same time*/
 460         for (i = 0; i < PAGE_SIZE/2; i++) {
 461                 *(img + i) = (buf[i] << 5) & 0xE0E0;
 462                 csum += *(img + i);
 463         }
 464         return csum;
 465 }
 466 
 467 /* this is called back from the deferred io workqueue */
 468 static void metronomefb_dpy_deferred_io(struct fb_info *info,
 469                                 struct list_head *pagelist)
 470 {
 471         u16 cksum;
 472         struct page *cur;
 473         struct fb_deferred_io *fbdefio = info->fbdefio;
 474         struct metronomefb_par *par = info->par;
 475 
 476         /* walk the written page list and swizzle the data */
 477         list_for_each_entry(cur, &fbdefio->pagelist, lru) {
 478                 cksum = metronomefb_dpy_update_page(par,
 479                                         (cur->index << PAGE_SHIFT));
 480                 par->metromem_img_csum -= par->csum_table[cur->index];
 481                 par->csum_table[cur->index] = cksum;
 482                 par->metromem_img_csum += cksum;
 483         }
 484 
 485         metronome_display_cmd(par);
 486 }
 487 
 488 static void metronomefb_fillrect(struct fb_info *info,
 489                                    const struct fb_fillrect *rect)
 490 {
 491         struct metronomefb_par *par = info->par;
 492 
 493         sys_fillrect(info, rect);
 494         metronomefb_dpy_update(par);
 495 }
 496 
 497 static void metronomefb_copyarea(struct fb_info *info,
 498                                    const struct fb_copyarea *area)
 499 {
 500         struct metronomefb_par *par = info->par;
 501 
 502         sys_copyarea(info, area);
 503         metronomefb_dpy_update(par);
 504 }
 505 
 506 static void metronomefb_imageblit(struct fb_info *info,
 507                                 const struct fb_image *image)
 508 {
 509         struct metronomefb_par *par = info->par;
 510 
 511         sys_imageblit(info, image);
 512         metronomefb_dpy_update(par);
 513 }
 514 
 515 /*
 516  * this is the slow path from userspace. they can seek and write to
 517  * the fb. it is based on fb_sys_write
 518  */
 519 static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
 520                                 size_t count, loff_t *ppos)
 521 {
 522         struct metronomefb_par *par = info->par;
 523         unsigned long p = *ppos;
 524         void *dst;
 525         int err = 0;
 526         unsigned long total_size;
 527 
 528         if (info->state != FBINFO_STATE_RUNNING)
 529                 return -EPERM;
 530 
 531         total_size = info->fix.smem_len;
 532 
 533         if (p > total_size)
 534                 return -EFBIG;
 535 
 536         if (count > total_size) {
 537                 err = -EFBIG;
 538                 count = total_size;
 539         }
 540 
 541         if (count + p > total_size) {
 542                 if (!err)
 543                         err = -ENOSPC;
 544 
 545                 count = total_size - p;
 546         }
 547 
 548         dst = (void __force *)(info->screen_base + p);
 549 
 550         if (copy_from_user(dst, buf, count))
 551                 err = -EFAULT;
 552 
 553         if  (!err)
 554                 *ppos += count;
 555 
 556         metronomefb_dpy_update(par);
 557 
 558         return (err) ? err : count;
 559 }
 560 
 561 static struct fb_ops metronomefb_ops = {
 562         .owner          = THIS_MODULE,
 563         .fb_write       = metronomefb_write,
 564         .fb_fillrect    = metronomefb_fillrect,
 565         .fb_copyarea    = metronomefb_copyarea,
 566         .fb_imageblit   = metronomefb_imageblit,
 567 };
 568 
 569 static struct fb_deferred_io metronomefb_defio = {
 570         .delay          = HZ,
 571         .deferred_io    = metronomefb_dpy_deferred_io,
 572 };
 573 
 574 static int metronomefb_probe(struct platform_device *dev)
 575 {
 576         struct fb_info *info;
 577         struct metronome_board *board;
 578         int retval = -ENOMEM;
 579         int videomemorysize;
 580         unsigned char *videomemory;
 581         struct metronomefb_par *par;
 582         const struct firmware *fw_entry;
 583         int i;
 584         int panel_type;
 585         int fw, fh;
 586         int epd_dt_index;
 587 
 588         /* pick up board specific routines */
 589         board = dev->dev.platform_data;
 590         if (!board)
 591                 return -EINVAL;
 592 
 593         /* try to count device specific driver, if can't, platform recalls */
 594         if (!try_module_get(board->owner))
 595                 return -ENODEV;
 596 
 597         info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
 598         if (!info)
 599                 goto err;
 600 
 601         /* we have two blocks of memory.
 602         info->screen_base which is vm, and is the fb used by apps.
 603         par->metromem which is physically contiguous memory and
 604         contains the display controller commands, waveform,
 605         processed image data and padding. this is the data pulled
 606         by the device's LCD controller and pushed to Metronome.
 607         the metromem memory is allocated by the board driver and
 608         is provided to us */
 609 
 610         panel_type = board->get_panel_type();
 611         switch (panel_type) {
 612         case 6:
 613                 epd_dt_index = 0;
 614                 break;
 615         case 8:
 616                 epd_dt_index = 1;
 617                 break;
 618         case 97:
 619                 epd_dt_index = 2;
 620                 break;
 621         default:
 622                 dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
 623                 epd_dt_index = 0;
 624                 break;
 625         }
 626 
 627         fw = epd_frame_table[epd_dt_index].fw;
 628         fh = epd_frame_table[epd_dt_index].fh;
 629 
 630         /* we need to add a spare page because our csum caching scheme walks
 631          * to the end of the page */
 632         videomemorysize = PAGE_SIZE + (fw * fh);
 633         videomemory = vzalloc(videomemorysize);
 634         if (!videomemory)
 635                 goto err_fb_rel;
 636 
 637         info->screen_base = (char __force __iomem *)videomemory;
 638         info->fbops = &metronomefb_ops;
 639 
 640         metronomefb_fix.line_length = fw;
 641         metronomefb_var.xres = fw;
 642         metronomefb_var.yres = fh;
 643         metronomefb_var.xres_virtual = fw;
 644         metronomefb_var.yres_virtual = fh;
 645         info->var = metronomefb_var;
 646         info->fix = metronomefb_fix;
 647         info->fix.smem_len = videomemorysize;
 648         par = info->par;
 649         par->info = info;
 650         par->board = board;
 651         par->dt = epd_dt_index;
 652         init_waitqueue_head(&par->waitq);
 653 
 654         /* this table caches per page csum values. */
 655         par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
 656         if (!par->csum_table)
 657                 goto err_vfree;
 658 
 659         /* the physical framebuffer that we use is setup by
 660          * the platform device driver. It will provide us
 661          * with cmd, wfm and image memory in a contiguous area. */
 662         retval = board->setup_fb(par);
 663         if (retval) {
 664                 dev_err(&dev->dev, "Failed to setup fb\n");
 665                 goto err_csum_table;
 666         }
 667 
 668         /* after this point we should have a framebuffer */
 669         if ((!par->metromem_wfm) ||  (!par->metromem_img) ||
 670                 (!par->metromem_dma)) {
 671                 dev_err(&dev->dev, "fb access failure\n");
 672                 retval = -EINVAL;
 673                 goto err_csum_table;
 674         }
 675 
 676         info->fix.smem_start = par->metromem_dma;
 677 
 678         /* load the waveform in. assume mode 3, temp 31 for now
 679                 a) request the waveform file from userspace
 680                 b) process waveform and decode into metromem */
 681         retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
 682         if (retval < 0) {
 683                 dev_err(&dev->dev, "Failed to get waveform\n");
 684                 goto err_csum_table;
 685         }
 686 
 687         retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
 688                                 par);
 689         release_firmware(fw_entry);
 690         if (retval < 0) {
 691                 dev_err(&dev->dev, "Failed processing waveform\n");
 692                 goto err_csum_table;
 693         }
 694 
 695         retval = board->setup_irq(info);
 696         if (retval)
 697                 goto err_csum_table;
 698 
 699         retval = metronome_init_regs(par);
 700         if (retval < 0)
 701                 goto err_free_irq;
 702 
 703         info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
 704 
 705         info->fbdefio = &metronomefb_defio;
 706         fb_deferred_io_init(info);
 707 
 708         retval = fb_alloc_cmap(&info->cmap, 8, 0);
 709         if (retval < 0) {
 710                 dev_err(&dev->dev, "Failed to allocate colormap\n");
 711                 goto err_free_irq;
 712         }
 713 
 714         /* set cmap */
 715         for (i = 0; i < 8; i++)
 716                 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
 717         memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
 718         memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
 719 
 720         retval = register_framebuffer(info);
 721         if (retval < 0)
 722                 goto err_cmap;
 723 
 724         platform_set_drvdata(dev, info);
 725 
 726         dev_dbg(&dev->dev,
 727                 "fb%d: Metronome frame buffer device, using %dK of video"
 728                 " memory\n", info->node, videomemorysize >> 10);
 729 
 730         return 0;
 731 
 732 err_cmap:
 733         fb_dealloc_cmap(&info->cmap);
 734 err_free_irq:
 735         board->cleanup(par);
 736 err_csum_table:
 737         vfree(par->csum_table);
 738 err_vfree:
 739         vfree(videomemory);
 740 err_fb_rel:
 741         framebuffer_release(info);
 742 err:
 743         module_put(board->owner);
 744         return retval;
 745 }
 746 
 747 static int metronomefb_remove(struct platform_device *dev)
 748 {
 749         struct fb_info *info = platform_get_drvdata(dev);
 750 
 751         if (info) {
 752                 struct metronomefb_par *par = info->par;
 753 
 754                 unregister_framebuffer(info);
 755                 fb_deferred_io_cleanup(info);
 756                 fb_dealloc_cmap(&info->cmap);
 757                 par->board->cleanup(par);
 758                 vfree(par->csum_table);
 759                 vfree((void __force *)info->screen_base);
 760                 module_put(par->board->owner);
 761                 dev_dbg(&dev->dev, "calling release\n");
 762                 framebuffer_release(info);
 763         }
 764         return 0;
 765 }
 766 
 767 static struct platform_driver metronomefb_driver = {
 768         .probe  = metronomefb_probe,
 769         .remove = metronomefb_remove,
 770         .driver = {
 771                 .name   = "metronomefb",
 772         },
 773 };
 774 module_platform_driver(metronomefb_driver);
 775 
 776 module_param(user_wfm_size, uint, 0);
 777 MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
 778 
 779 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
 780 MODULE_AUTHOR("Jaya Kumar");
 781 MODULE_LICENSE("GPL");

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