/* here we decode the incoming waveform file and populate metromem */ staticint load_waveform(u8 *mem, size_t size, int m, int t, struct metronomefb_par *par)
{ int tta; int wmta; int trn = 0; int i; unsignedchar v;
u8 cksum; int cksum_idx; int wfm_idx, owfm_idx; int mem_idx = 0; struct waveform_hdr *wfm_hdr;
u8 *metromem = par->metromem_wfm; struct device *dev = par->info->device;
if (user_wfm_size)
epd_frame_table[par->dt].wfm_size = user_wfm_size;
if (wfm_hdr->fvsn != 1) {
dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn); return -EINVAL;
} if (wfm_hdr->luts != 0) {
dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts); return -EINVAL;
}
cksum = calc_cksum(32, 47, mem); if (cksum != wfm_hdr->wfm_cs) {
dev_err(dev, "Error: bad cksum %x != %x\n", cksum,
wfm_hdr->wfm_cs); return -EINVAL;
}
wfm_hdr->mc += 1;
wfm_hdr->trc += 1; for (i = 0; i < 5; i++) { if (*(wfm_hdr->stuff2a + i) != 0) {
dev_err(dev, "Error: unexpected value in padding\n"); return -EINVAL;
}
}
/* calculating trn. trn is something used to index into thewaveform.presumablyselectingtherightoneforthe desiredtemperature.itworksouttheoffsetofthefirst
v that exceeds the specified temperature */ if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size) return -EINVAL;
for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) { if (mem[i] > t) {
trn = i - sizeof(*wfm_hdr) - 1; break;
}
}
/* check temperature range table checksum */
cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1; if (cksum_idx >= size) return -EINVAL;
cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); if (cksum != mem[cksum_idx]) {
dev_err(dev, "Error: bad temperature range table cksum" " %x != %x\n", cksum, mem[cksum_idx]); return -EINVAL;
}
/* check waveform temperature table address checksum */
tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
cksum_idx = tta + trn*4 + 3; if (cksum_idx >= size) return -EINVAL;
cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); if (cksum != mem[cksum_idx]) {
dev_err(dev, "Error: bad temperature table address cksum" " %x != %x\n", cksum, mem[cksum_idx]); return -EINVAL;
}
/* here we do the real work of putting the waveform into the
metromem buffer. this does runlength decoding of the waveform */
wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
owfm_idx = wfm_idx; if (wfm_idx >= size) return -EINVAL; while (wfm_idx < size) { unsignedchar rl;
v = mem[wfm_idx++]; if (v == wfm_hdr->swtb) { while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
wfm_idx < size)
metromem[mem_idx++] = v;
continue;
}
if (v == wfm_hdr->endb) break;
rl = mem[wfm_idx++]; for (i = 0; i <= rl; i++)
metromem[mem_idx++] = v;
}
cksum_idx = wfm_idx; if (cksum_idx >= size) return -EINVAL;
cksum = calc_cksum(owfm_idx, cksum_idx, mem); if (cksum != mem[cksum_idx]) {
dev_err(dev, "Error: bad waveform data cksum" " %x != %x\n", cksum, mem[cksum_idx]); return -EINVAL;
}
par->frame_count = (mem_idx/64);
/* setup display command wecan'timmediatelysettheopcodesincethecontroller willtryparsethecommandbeforewe'vesetitallup
so we just set cs here and set the opcode at the end */
staticint metronome_powerup_cmd(struct metronomefb_par *par)
{ int i;
u16 cs;
/* setup power up command */
par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
cs = par->metromem_cmd->opcode;
/* set pwr1,2,3 to 1024 */ for (i = 0; i < 3; i++) {
par->metromem_cmd->args[i] = 1024;
cs += par->metromem_cmd->args[i];
}
/* the rest are 0 */
memset(&par->metromem_cmd->args[i], 0,
(ARRAY_SIZE(par->metromem_cmd->args) - i) * 2);
par->metromem_cmd->csum = cs;
msleep(1);
par->board->set_rst(par, 1);
msleep(1);
par->board->set_stdby(par, 1);
return par->board->met_wait_event(par);
}
staticint metronome_config_cmd(struct metronomefb_par *par)
{ /* setup config command wecan'timmediatelysettheopcodesincethecontroller
will try parse the command before we've set it all up */
memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, sizeof(epd_frame_table[par->dt].config)); /* the rest are 0 */
memset(&par->metromem_cmd->args[4], 0,
(ARRAY_SIZE(par->metromem_cmd->args) - 4) * 2);
staticint metronome_init_cmd(struct metronomefb_par *par)
{ int i;
u16 cs;
/* setup init command wecan'timmediatelysettheopcodesincethecontroller willtryparsethecommandbeforewe'vesetitallup
so we just set cs here and set the opcode at the end */
cs = 0xCC20;
/* set the args ( 2 bytes ) for init */
i = 0;
par->metromem_cmd->args[i] = 0;
cs += par->metromem_cmd->args[i++];
/* the rest are 0 */
memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
/* swizzle from vm to metromem and recalc cksum at the same time*/ for (i = 0; i < PAGE_SIZE/2; i++) {
*(img + i) = (buf[i] << 5) & 0xE0E0;
csum += *(img + i);
} return csum;
}
/* this is called back from the deferred io workqueue */ staticvoid metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist)
{
u16 cksum; struct fb_deferred_io_pageref *pageref; struct metronomefb_par *par = info->par;
/* walk the written page list and swizzle the data */
list_for_each_entry(pageref, pagereflist, list) { unsignedlong pgoffset = pageref->offset >> PAGE_SHIFT;
cksum = metronomefb_dpy_update_page(par, pageref->offset);
par->metromem_img_csum -= par->csum_table[pgoffset];
par->csum_table[pgoffset] = cksum;
par->metromem_img_csum += cksum;
}
staticint metronomefb_probe(struct platform_device *dev)
{ struct fb_info *info; struct metronome_board *board; int retval = -ENOMEM; int videomemorysize; unsignedchar *videomemory; struct metronomefb_par *par; conststruct firmware *fw_entry; int i; int panel_type; int fw, fh; int epd_dt_index;
/* pick up board specific routines */
board = dev->dev.platform_data; if (!board) return -EINVAL;
/* try to count device specific driver, if can't, platform recalls */ if (!try_module_get(board->owner)) return -ENODEV;
info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); if (!info) goto err;
/* we have two blocks of memory. info->screen_bufferwhichisvm,andisthefbusedbyapps. par->metromemwhichisphysicallycontiguousmemoryand containsthedisplaycontrollercommands,waveform, processedimagedataandpadding.thisisthedatapulled bythedevice'sLCDcontrollerandpushedtoMetronome. themetromemmemoryisallocatedbytheboarddriverand
is provided to us */
/* we need to add a spare page because our csum caching scheme walks
* to the end of the page */
videomemorysize = PAGE_SIZE + (fw * fh);
videomemory = vzalloc(videomemorysize); if (!videomemory) goto err_fb_rel;
/* this table caches per page csum values. */
par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); if (!par->csum_table) goto err_vfree;
/* the physical framebuffer that we use is setup by *theplatformdevicedriver.Itwillprovideus
* with cmd, wfm and image memory in a contiguous area. */
retval = board->setup_fb(par); if (retval) {
dev_err(&dev->dev, "Failed to setup fb\n"); goto err_csum_table;
}
/* after this point we should have a framebuffer */ if ((!par->metromem_wfm) || (!par->metromem_img) ||
(!par->metromem_dma)) {
dev_err(&dev->dev, "fb access failure\n");
retval = -EINVAL; goto err_csum_table;
}
info->fix.smem_start = par->metromem_dma;
/* load the waveform in. assume mode 3, temp 31 for now a)requestthewaveformfilefromuserspace
b) process waveform and decode into metromem */
retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); if (retval < 0) {
dev_err(&dev->dev, "Failed to get waveform\n"); goto err_csum_table;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.