How to get the raw data of CR2 image using LibRaw(c++) - c

LibRaw is a library for reading RAW files from digital photo cameras (CRW/CR2, NEF, RAF, DNG, MOS, KDC, DCR, etc.; virtually all RAW formats are supported).
I want to know how to use LibRaw to get the raw data of a Canon CR2 image.
typedef struct
{
ushort (*image)[4] ;
libraw_image_sizes_t sizes;
libraw_iparams_t idata;
libraw_lensinfo_t lens;
libraw_makernotes_t makernotes;
libraw_shootinginfo_t shootinginfo;
libraw_output_params_t params;
unsigned int progress_flags;
unsigned int process_warnings;
libraw_colordata_t color;
libraw_imgother_t other;
libraw_thumbnail_t thumbnail;
libraw_rawdata_t rawdata;
void *parent_class;
} libraw_data_t;
typedef struct
{
void *raw_alloc;
ushort *raw_image;
ushort (*color4_image)[4] ;
ushort (*color3_image)[3];
float *float_image;
float (*float3_image)[3];
float (*float4_image)[4];
short (*ph1_cblack)[2];//
short (*ph1_rblack)[2];//
libraw_iparams_t iparams;//
libraw_image_sizes_t sizes;//
libraw_internal_output_params_t ioparams;//
libraw_colordata_t color;//
} libraw_rawdata_t;
This is the data structure of RAW data, I don't know which structure the most primitive data is stored in.

I have already got the answer, now download it below, I hope to help those in need.
int i,ret,verbose = 0,output_thumbs = 0;
char outfn [1024],thumbfn [1024];
//Create object
LibRaw RawProcessor;
putenv((char *)"TZ = UTC+8");
//
#define P1 RawProcessor.imgdata.idata
#define S RawProcessor.imgdata.sizes
#define C RawProcessor.imgdata.color
#define T RawProcessor.imgdata.thumbnail
#define P2 RawProcessor.imgdata.other
#define OUT RawProcessor.imgdata.params
OUT.output_tiff = 0; //
OUT.no_auto_scale=1;//
OUT.no_auto_bright=1;//
OUT.output_bps=16;//16bit
OUT.output_color=0;//RAW
//openfile
if((ret = RawProcessor.open_file(szFile))!= LIBRAW_SUCCESS)
{
fprintf(stderr,"Can not open%s:%s\n",szFile,libraw_strerror(ret));
RawProcessor.recycle();
return FALSE;
}
//RAW size
int height=S.raw_height;
int width=S.raw_width;
//image info
memset(LinsnData.imgdata.make,0,64*sizeof(char));
memset(LinsnData.imgdata.model,0,64*sizeof(char));
memcpy(LinsnData.imgdata.make,P1.make,strlen(P1.make));
memcpy(LinsnData.imgdata.model,P1.model,strlen(P1.model));
LinsnData.imgdata.aperture=P2.aperture;
LinsnData.imgdata.iso_speed=P2.iso_speed;
LinsnData.imgdata.shutter=P2.shutter;
char timestamp[64]= {0};
tm* local = localtime(&P2.timestamp); //
strftime(LinsnData.imgdata.timestamp, 64, "%Y-%m-%d %H:%M:%S", local);
/***************************************************************************************************/
//
if((ret = RawProcessor.unpack())!= LIBRAW_SUCCESS)
{
fprintf(stderr,"Can not unpack_thumb%s:%s\n",szFile,libraw_strerror(ret));
//if(LIBRAW_FATAL_ERROR(ret))
goto end;
}
WORD *bmpData=RawProcessor.imgdata.rawdata.raw_image;
int nWidth = width/2;
int nHeight = height/2;
WORD *m_bmpDataR = new WORD[nWidth*nHeight];
WORD *m_bmpDataG = new WORD[nWidth*nHeight];
WORD *m_bmpDataB = new WORD[nWidth*nHeight];
//
for(int i=0;i<nHeight;i++)
{
for(int j=0;j<nWidth;j++)
{
m_bmpDataB[i*nWidth+j] = bmpData[i*nWidth*4+nWidth*2+j*2+1];
m_bmpDataG[i*nWidth+j] = ((bmpData[i*nWidth*4+nWidth*2+j*2]+bmpData[i*nWidth*4+j*2+1])>>1);
m_bmpDataR[i*nWidth+j] = bmpData[i*nWidth*4+j*2];
}
}

Related

Linux DMA: Using the DMAengine for scatter-gather transactions

I try to use the DMAengine API from a custom kernel driver to perform a scatter-gather operation. I have a contiguous memory region as source and I want to copy its data in several distributed buffers through a scatterlist structure. The DMA controller is the PL330 one that supports the DMAengine API (see PL330 DMA controller).
My test code is the following:
In my driver header file (test_driver.h):
#ifndef __TEST_DRIVER_H__
#define __TEST_DRIVER_H__
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/of_dma.h>
#define SG_ENTRIES 3
#define BUF_SIZE 16
#define DEV_BUF 0x10000000
struct dma_block {
void * data;
int size;
};
struct dma_private_info {
struct sg_table sgt;
struct dma_block * blocks;
int nblocks;
int dma_started;
struct dma_chan * dma_chan;
struct dma_slave_config dma_config;
struct dma_async_tx_descriptor * dma_desc;
dma_cookie_t cookie;
};
struct test_platform_device {
struct platform_device * pdev;
struct dma_private_info dma_priv;
};
#define _get_devp(tdev) (&((tdev)->pdev->dev))
#define _get_dmapip(tdev) (&((tdev)->dma_priv))
int dma_stop(struct test_platform_device * tdev);
int dma_start(struct test_platform_device * tdev);
int dma_start_block(struct test_platform_device * tdev);
int dma_init(struct test_platform_device * tdev);
int dma_exit(struct test_platform_device * tdev);
#endif
In my source that contains the dma functions (dma_functions.c):
#include <linux/slab.h>
#include "test_driver.h"
#define BARE_RAM_BASE 0x10000000
#define BARE_RAM_SIZE 0x10000000
struct ram_bare {
uint32_t * __iomem map;
uint32_t base;
uint32_t size;
};
static void dma_sg_check(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
uint32_t * buf;
unsigned int bufsize;
int nwords;
int nbytes_word = sizeof(uint32_t);
int nblocks;
struct ram_bare ramb;
uint32_t * p;
int i;
int j;
ramb.map = ioremap(BARE_RAM_BASE,BARE_RAM_SIZE);
ramb.base = BARE_RAM_BASE;
ramb.size = BARE_RAM_SIZE;
dev_info(dev,"nblocks: %d \n",dma_priv->nblocks);
p = ramb.map;
nblocks = dma_priv->nblocks;
for( i = 0 ; i < nblocks ; i++ ) {
buf = (uint32_t *) dma_priv->blocks[i].data;
bufsize = dma_priv->blocks[i].size;
nwords = dma_priv->blocks[i].size/nbytes_word;
dev_info(dev,"block[%d],size %d: ",i,bufsize);
for ( j = 0 ; j < nwords; j++, p++) {
dev_info(dev,"DMA: 0x%x, RAM: 0x%x",buf[j],ioread32(p));
}
}
iounmap(ramb.map);
}
static int dma_sg_exit(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
int ret = 0;
int i;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
kfree(dma_priv->blocks[i].data);
}
kfree(dma_priv->blocks);
sg_free_table(&(dma_priv->sgt));
return ret;
}
int dma_stop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
dma_unmap_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
dma_sg_exit(tdev);
dma_priv->dma_started = 0;
return ret;
}
static void dma_callback(void * param)
{
enum dma_status dma_stat;
struct test_platform_device * tdev = (struct test_platform_device *) param;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dev_info(dev,"Checking the DMA state....\n");
dma_stat = dma_async_is_tx_complete(dma_priv->dma_chan,\
dma_priv->cookie, NULL, NULL);
if(dma_stat == DMA_COMPLETE) {
dev_info(dev,"DMA complete! \n");
dma_sg_check(tdev);
dma_stop(tdev);
} else if (unlikely(dma_stat == DMA_ERROR)) {
dev_info(dev,"DMA error! \n");
dma_stop(tdev);
}
}
static void dma_busy_loop(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
enum dma_status status;
int status_change = -1;
do {
status = dma_async_is_tx_complete(dma_priv->dma_chan, dma_priv->cookie, NULL, NULL);
switch(status) {
case DMA_COMPLETE:
if(status_change != 0)
dev_info(dev,"DMA status: COMPLETE\n");
status_change = 0;
break;
case DMA_PAUSED:
if (status_change != 1)
dev_info(dev,"DMA status: PAUSED\n");
status_change = 1;
break;
case DMA_IN_PROGRESS:
if(status_change != 2)
dev_info(dev,"DMA status: IN PROGRESS\n");
status_change = 2;
break;
case DMA_ERROR:
if (status_change != 3)
dev_info(dev,"DMA status: ERROR\n");
status_change = 3;
break;
default:
dev_info(dev,"DMA status: UNKNOWN\n");
status_change = -1;
break;
}
} while(status != DMA_COMPLETE);
dev_info(dev,"DMA transaction completed! \n");
}
static int dma_sg_init(struct test_platform_device * tdev)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct scatterlist *sg;
int ret = 0;
int i;
ret = sg_alloc_table(&(dma_priv->sgt), SG_ENTRIES, GFP_ATOMIC);
if(ret)
goto out_mem2;
dma_priv->nblocks = SG_ENTRIES;
dma_priv->blocks = (struct dma_block *) kmalloc(dma_priv->nblocks\
*sizeof(struct dma_block), GFP_ATOMIC);
if(dma_priv->blocks == NULL)
goto out_mem1;
for( i = 0 ; i < dma_priv->nblocks ; i++ ) {
dma_priv->blocks[i].size = BUF_SIZE;
dma_priv->blocks[i].data = kmalloc(dma_priv->blocks[i].size, GFP_ATOMIC);
if(dma_priv->blocks[i].data == NULL)
goto out_mem3;
}
for_each_sg(dma_priv->sgt.sgl, sg, dma_priv->sgt.nents, i)
sg_set_buf(sg,dma_priv->blocks[i].data,dma_priv->blocks[i].size);
return ret;
out_mem3:
i--;
while(i >= 0)
kfree(dma_priv->blocks[i].data);
kfree(dma_priv->blocks);
out_mem2:
sg_free_table(&(dma_priv->sgt));
out_mem1:
ret = -ENOMEM;
return ret;
}
static int _dma_start(struct test_platform_device * tdev,int block)
{
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
int ret = 0;
int sglen;
/* Step 1: Allocate and initialize the SG list */
dma_sg_init(tdev);
/* Step 2: Map the SG list */
sglen = dma_map_sg(dev,dma_priv->sgt.sgl,\
dma_priv->sgt.nents, DMA_FROM_DEVICE);
if(! sglen)
goto out2;
/* Step 3: Configure the DMA */
(dma_priv->dma_config).direction = DMA_DEV_TO_MEM;
(dma_priv->dma_config).src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
(dma_priv->dma_config).src_maxburst = 1;
(dma_priv->dma_config).src_addr = (dma_addr_t) DEV_BUF;
dmaengine_slave_config(dma_priv->dma_chan, \
&(dma_priv->dma_config));
/* Step 4: Prepare the SG descriptor */
dma_priv->dma_desc = dmaengine_prep_slave_sg(dma_priv->dma_chan, \
dma_priv->sgt.sgl, dma_priv->sgt.nents, DMA_DEV_TO_MEM, \
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (dma_priv->dma_desc == NULL) {
dev_err(dev,"DMA could not assign a descriptor! \n");
goto out1;
}
/* Step 5: Set the callback method */
(dma_priv->dma_desc)->callback = dma_callback;
(dma_priv->dma_desc)->callback_param = (void *) tdev;
/* Step 6: Put the DMA descriptor in the queue */
dma_priv->cookie = dmaengine_submit(dma_priv->dma_desc);
/* Step 7: Fires the DMA transaction */
dma_async_issue_pending(dma_priv->dma_chan);
dma_priv->dma_started = 1;
if(block)
dma_busy_loop(tdev);
return ret;
out1:
dma_stop(tdev);
out2:
ret = -1;
return ret;
}
int dma_start(struct test_platform_device * tdev) {
return _dma_start(tdev,0);
}
int dma_start_block(struct test_platform_device * tdev) {
return _dma_start(tdev,1);
}
int dma_init(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
struct device * dev = _get_devp(tdev);
dma_priv->dma_chan = dma_request_slave_channel(dev, \
"dma_chan0");
if (dma_priv->dma_chan == NULL) {
dev_err(dev,"DMA channel busy! \n");
ret = -1;
}
dma_priv->dma_started = 0;
return ret;
}
int dma_exit(struct test_platform_device * tdev)
{
int ret = 0;
struct dma_private_info * dma_priv = _get_dmapip(tdev);
if(dma_priv->dma_started) {
dmaengine_terminate_all(dma_priv->dma_chan);
dma_stop(tdev);
dma_priv->dma_started = 0;
}
if(dma_priv->dma_chan != NULL)
dma_release_channel(dma_priv->dma_chan);
return ret;
}
In my driver source file (test_driver.c):
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include "test_driver.h"
static int dma_block=0;
module_param_named(dma_block, dma_block, int, 0444);
static struct test_platform_device tdev;
static struct of_device_id test_of_match[] = {
{ .compatible = "custom,test-driver-1.0", },
{}
};
static int test_probe(struct platform_device *op)
{
int ret = 0;
struct device * dev = &(op->dev);
const struct of_device_id *match = of_match_device(test_of_match, &op->dev);
if (!match)
return -EINVAL;
tdev.pdev = op;
dma_init(&tdev);
if(dma_block)
ret = dma_start_block(&tdev);
else
ret = dma_start(&tdev);
if(ret) {
dev_err(dev,"Error to start DMA transaction! \n");
} else {
dev_info(dev,"DMA OK! \n");
}
return ret;
}
static int test_remove(struct platform_device *op)
{
dma_exit(&tdev);
return 0;
}
static struct platform_driver test_platform_driver = {
.probe = test_probe,
.remove = test_remove,
.driver = {
.name = "test-driver",
.owner = THIS_MODULE,
.of_match_table = test_of_match,
},
};
static int test_init(void)
{
platform_driver_register(&test_platform_driver);
return 0;
}
static void test_exit(void)
{
platform_driver_unregister(&test_platform_driver);
}
module_init(test_init);
module_exit(test_exit);
MODULE_AUTHOR("klyone");
MODULE_DESCRIPTION("DMA SG test module");
MODULE_LICENSE("GPL");
However, the DMA never calls my callback function and I do not have any idea why it happens. Maybe, I am misunderstanding something...
Could anyone help me?
Thanks in advance.
Caveat: I don't have a definitive solution for you, but merely some observations and suggestions on how to debug this [based on many years of experience writing/debugging linux device drivers].
I presume you believe the callback is not being done because you don't get any printk messages. But, the callback is the only place that has them. But, is the printk level set high enough to see the messages? I'd add a dev_info to your module init, to prove it prints as expected.
Also, you [probably] won't get a callback if dma_start doesn't work as expected, so I'd add some dev_info calls there, too (e.g. before and after the call in step 7). I also notice that not all calls in dma_start check error returns [may be fine or void return, just mentioning in case you missed one]
At this point, it should be noted that there are really two questions here: (1) Did your DMA request start successfully [and complete]? (2) Did you get a callback?
So, I'd split off some code from dma_complete into (e.g.) dma_test_done. The latter does the same checking but only prints the "complete" message. You can call this in a poll mode to verify DMA completion.
So, if you [eventually] get a completion, then the problem reduces to why you didn't get the callback. If, however, you don't [even] get a completion, that's an even more fundamental problem.
This reminds me. You didn't show any code that calls dma_start or how you wait for the completion. I presume that if your callback were working, it would issue a wakeup of some sort that the base level would wait on. Or, the callback would do the request deallocate/cleanup (i.e. more code you'd write)
At step 7, you're calling dma_async_issue_pending, which should call pl330_issue_pending. pl330_issue_pending will call pl330_tasklet.
pl330_tasklet is a tasklet function, but it can also be called directly [to kick off DMA when there are no active requests].
pl330_tasklet will loop on its "work" queue and move any completed items to its "completed" queue. It then tries to start new requests. It then loops on its completed queue and issues the callbacks.
pl330_tasklet grabs the callback pointer, but if it's null it is silently ignored. You've set a callback, but it might be good to verify that where you set the callback is the same place [or propagates to] the place where pl330_tasklet will fetch it from.
When you make the call, everything may be busy, so there are no completed requests, no room to start a new request, so nothing to complete. In that case, pl330_tasklet will be called again later.
So, when dma_async_issue_pending returns, nothing may have happened yet. This is quite probable for your case.
pl330_tasklet tries to start new DMA by calling fill_queue. It will check that a descriptor is not [already] busy by looking at status != BUSY. So, you may wish to verify that yours has the correct value. Otherwise, you'd never get a callback [or even any DMA start].
Then, fill_queue will try to start the request via pl330_submit_req. But, that can return an error (e.g. queue already full), so, again, things are deferred.
For reference, notice the following comment at the top of pl330_submit_req:
Submit a list of xfers after which the client wants notification.
Client is not notified after each xfer unit, just once after all
xfer units are done or some error occurs.
What I'd do is start hacking up pl330.c and add debug messages and cross-checking. If your system is such that pl330 is servicing many other requests, you might limit the debug messages by checking that the device's private data pointer matches yours.
In particular, you'd like to get a message when your request actually gets started, so you could add a debug message to the end of pl330_submit_req
Then, adding messages within pl330_tasklet for requests will help, too.
Those are two good starting points. But, don't be afraid to add more printk calls as needed. You may be surprised by what gets called [or doesn't get called] or in what order.
UPDATE:
If I install the kernel module with the blocking behaviour, everything is initialized well. However, the dma_busy_loop function shows that the DMA descriptor is always IN PROGESS and the DMA transaction never completes. For this reason, the callback function is not executed. What could be happening?
Did a little more research. Cookies are just sequence numbers that increment. For example, if you issue a request that gets broken up into [say] 10 separate scatter/gather operations [descriptors], each one gets a unique cookie value. The cookie return value is the latest/last of the bunch (e.g. 10).
When you're calling (1) dma_async_is_tx_complete, (2) it calls chan->device->device_tx_status, (3) which is pl330_tx_status, (4) which calls dma_cookie_status
Side note/tip: When I was tracking this down, I just kept flipping back and forth between dmaengine.h and pl330.c. It was like: Look at (1), it calls (2). Where is that set? In pl330.c, I presume. So, I grepped for the string and got the name of pl330's function (i.e. (3)). So, I go there, and see that it does (4). So ... Back to dmaengine.h ...
However, when you make the outer call, you're ignoring [setting to NULL] the last two arguments. These can be useful because they return the "last" and "used" cookies. So, even if you don't get full completion, these values could change and show partial progress.
One of them should eventually be >= to the "return" cookie value. (i.e.) The entire operation should be complete. So, this will help differentiate what may be happening.
Also, note that in dmaengine.h, right below dma_async_is_tx_complete, there is dma_async_is_complete. This function is what decides whether to return DMA_COMPLETE or DMA_IN_PROGRESS, based on the cookie value you pass and the "last" and "used" cookie values. It's passive, and not used in the code path [AFAICT], but it does show how to calculate completion yourself.

How to use structs declared in the header and defined in source code by a function

I am trying to store the main features of my hardware configuration in one place, so I created structures for it. I declared them as typedef in a header file, and I want to create and define the actual structures in a function, that I can call when the application starts. (I am using an STM32F04 board with chibiOS running on it.)
Here is the header file:
#ifndef HW_INIT_INCLUDED
#define HW_INIT_INCLUDED
#include <mcuconf.h>
#include <hal.h>
#include <ch.h>
struct Recievers;
struct LEDs;
struct Ultrasonic;
typedef struct Recievers{
int iD;
int port;
int pinNumber;
} Reciever;
typedef struct LEDs{
int iD;
char port;
int pinNumber;
bool status;
float dutyCycleConstant;
} LED;
typedef struct Ultrasonic{
char port;
int pinNumber;
}Ultrasonic;
/*
Initaliases the values of hw parameters.
*/
void hardWareInit(struct Recievers Reciever, struct LEDs LED, struct Ultrasonic Ultrasonic);
#endif // HW_INIT_INCLUDED
and here is the source code:
#include <hw_init.h>
#include <stdlib.h>
void hardWareInit(struct Recievers Reciever, struct LEDs LED, struct Ultrasonic Ultrasonic)
{
Reciever Reciever1, Reciever2, Reciever3, Reciever4;
LED LED1, LED2, LED3;
Ultrasonic Ultrasonic1;
Reciever1.iD = 1;
Reciever1.port = GPIOF;
Reciever1.pinNumber = 1;
Reciever2.iD = 2;
Reciever2.port = GPIOG;
Reciever2.pinNumber = 1;
Reciever3.iD = 3;
Reciever3.port = GPIOI;
Reciever3.pinNumber = 1;
Reciever4.iD = 3;
Reciever4.port = GPIOE;
Reciever4.pinNumber = 1;
LED1.iD = 1;
LED1.port = GPIOD;
LED1.pinNumber = 16;
LED1.status = 0;
LED1.dutyCycleConstant = 0.3;
LED2.iD = 2;
LED1.port = GPIOD;
LED2.pinNumber = 16;
LED2.status = 0;
LED2.dutyCycleConstant = 0.3;
LED3.iD = 3;
LED1.port = GPIOD;
LED3.pinNumber = 16;
LED3.status = 0;
LED3.dutyCycleConstant = 0.3;
Ultrasonic1.port = GPIOC;
Ultrasonic1.pinNumber = 1;
}
When I try to compile, it basically gives these errors for every struct I try to create:
hw_init.c:8:5: warning: statement with no effect [-Wunused-value]
Reciever Reciever1;
^
hw_init.c:8:14: error: expected ';' before 'Reciever1'
Reciever Reciever1;
When I try to compile, it basically gives these errors for every struct I try to create:
hw_init.c:8:5: warning: statement with no effect [-Wunused-value] Reciever Reciever1;
hw_init.c:8:14: error: expected ';' before 'Reciever1' Reciever Reciever1;
You get the error message because you use the word Reciever for a typedef'd struct as well as the first function parameter:
void hardWareInit(struct Recievers Reciever, struct LEDs LED, struct Ultrasonic Ultrasonic)
You should use a diffent designator for the first parameter.
Further I suggest to name reciever to receiver.

Linux framebuffer driver and custom file operation

I implemented a framebuffer driver retrieved from a former project in Linux for an embedded system and what I need to do is quite simple: draw a small rectangle where the screen is touched.
In order to do this, I want to use the function xxxfb_fillrect() that you can find in the following driver code (some parts are omitted) :
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/console.h>
#define PCI_VENDOR_ID_XXX 0x10F610F6
#define PCI_DEVICE_ID_XXX 0x2864C826
#define PCI_CLASS_MASK 0x00FF
#define FB_NAME "MFCC8556_vfb_"
#define FB_MAJOR 29
#define VIDEOMEMSIZE (480*800*3)
#define FBIO_TEST _IO('F', 0x21)
/* Global variable */
/*
* Driver data
*/
//static char *videomemory;
static int fb_count = 3;
static u_long videomemorysize = VIDEOMEMSIZE;
/* array of framebuffer */
static struct fb_info **g_fb_list;
static struct fb_fix_screeninfo fix_default __initdata = {
.id = FB_NAME,
.smem_len = VIDEOMEMSIZE,
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static struct fb_var_screeninfo var_default __initdata = {
.xres = 800,
.yres = 480,
.xres_virtual = 800,
.yres_virtual = 480,
.bits_per_pixel = 24,
.red = {0, 8, 0},
.green = {0, 8, 0},
.blue = {0, 8, 0},
.grayscale = 0,
.activate = FB_ACTIVATE_TEST,
.height = -1,
.width = -1,
.pixclock = 30060,
.vmode = FB_VMODE_NONINTERLACED,
};
static int xxxfb_init(void);
static int register_fb(struct fb_info *info);
static int set_screen_base(struct fb_info* info);
static int init_fb_info(struct fb_info *info, struct fb_ops *fbops, unsigned int id_no);
static int alloc_fb_info (struct fb_info **info);
/* ------------ Accelerated Functions --------------------- */
/*
* We provide our own functions if we have hardware acceleration
* or non packed pixel format layouts. If we have no hardware
* acceleration, we can use a generic unaccelerated function. If using
* a pack pixel format just use the functions in cfb_*.c. Each file
* has one of the three different accel functions we support.
*/
/**
* xxxfb_fillrect - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
* Draws a rectangle on the screen.
*
* #info: frame buffer structure that represents a single frame buffer
* #region: The structure representing the rectangular region we
* wish to draw to.
*
* This drawing operation places/removes a retangle on the screen
* depending on the rastering operation with the value of color which
* is in the current color depth format.
*/
void xxxfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
{
/* Meaning of struct fb_fillrect
*
* #dx: The x and y coordinates of the upper left hand corner of the
* #dy: area we want to draw to.
* #width: How wide the rectangle is we want to draw.
* #height: How tall the rectangle is we want to draw.
* #color: The color to fill in the rectangle with.
* #rop: The raster operation. We can draw the rectangle with a COPY
* of XOR which provides erasing effect.
*/
struct fb_fillrect *tmp_fillrect;
/*ptr=(unsigned long*)info->screen_base;
//fill the screen base ///
for(i=0; i<800*10; i++){
*ptr=0x0000FF00;
ptr++;
}*/
printk(KERN_DEBUG "\nfb_fillrect()");
printk(KERN_DEBUG "\nFix Screen Info.id =%s\n", info->fix.id);
/* printk(KERN_INFO "\nstruct fb_fillrect:\n"
"dx = %d\n"
"dy = %d\n"
"width = %d\n"
"height = %d\n"
"color = 0x%08X\n"
"rop = 0x%X\n___\n"
, region->dx, region->dy, region->width, region->height, region->color, region->rop);
*/
// printk(KERN_INFO "_in fill_rectangle : screen_base = 0x%X\n0x_%02X_%02X_%02X_%02X\n...\n",(unsigned int)info->screen_base, *info->screen_base, *(info->screen_base+1), *(info->screen_base+2),*(info->screen_base+3));
tmp_fillrect = kmalloc(sizeof(struct fb_fillrect), GFP_KERNEL);
*tmp_fillrect = *region;
/*tmp_fillrect->dx=400;
tmp_fillrect->dy=200;
tmp_fillrect->width=100;
tmp_fillrect->height=50;
tmp_fillrect->color=0x0000FF00;
tmp_fillrect->rop=0x0;
*/
//tmp = copy_from_user(tmp_fillrect, region, sizeof(struct fb_fillrect));
printk(KERN_INFO "\nstruct fb_fillrect:\n"
"dx = %d\n"
"dy = %d\n"
"width = %d\n"
"height = %d\n"
"color = 0x%08X\n"
"rop = 0x%X\n___\n"
, tmp_fillrect->dx, tmp_fillrect->dy, tmp_fillrect->width, tmp_fillrect->height, tmp_fillrect->color, tmp_fillrect->rop);
//if (tmp) printk(KERN_ERR "**ERROR: copy_from_user = %d\n", tmp);
cfb_fillrect(info, region);
}
...
int xxxfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){
int ret = 0;
printk(KERN_INFO "fb_ioctl()");
mutex_lock(&info->lock);
switch(cmd) {
case FBIOGET_VSCREENINFO:
printk(KERN_DEBUG "FBIOGET_VSCREENINFO");
break;
case FBIOGET_FSCREENINFO:
printk(KERN_DEBUG "FBIOGET_FSCREENINFO");
break;
case FBIO_TEST:
printk(KERN_DEBUG "FBIO_TEST");
break;
default:
printk(KERN_DEBUG "ioctl DEFAULT");
break;
}
mutex_unlock(&info->lock);
return ret;
}
/*
* Frame buffer operations
*/
static struct fb_ops xxxfb_ops = {
.owner = THIS_MODULE,
.fb_open = xxxfb_open,
.fb_read = fb_sys_read,
.fb_write = fb_sys_write,
.fb_release = xxxfb_release,
.fb_check_var = xxxfb_check_var,
.fb_set_par = xxxfb_set_par,
//.fb_setcolreg = xxxfb_setcolreg,
.fb_blank = xxxfb_blank,
.fb_pan_display = xxxfb_pan_display,
.fb_fillrect = xxxfb_fillrect, /* Needed !!! */
.fb_copyarea = xxxfb_copyarea, /* Needed !!! */
.fb_imageblit = xxxfb_imageblit, /* Needed !!! */
.fb_cursor = xxxfb_cursor, /* Optional !!! */
.fb_sync = xxxfb_sync,
.fb_ioctl = xxxfb_ioctl,
.fb_mmap = xxxfb_mmap,
};
/* ------------------------------------------------------------------------- */
...
/*
* Modularization
*/
module_init(xxxfb_init);
module_exit(xxxfb_exit);
MODULE_LICENSE("GPL");
But the thing is, I have no idea how to call it. I ended up implementing the drawing of the rectangle manually without using this fb_fillrect().
I know this is not a usual open/rd/wr/... operation, but it is here. How do I use it ? Should I call it with ioctl()? If yes, why is fb_fillrect appearing in the frame buffer operations struct ?
Thank you in advance for your help.
The functions in fb_ops are low level operations not directly exposed to user-space. Instead, there is a fb_fops struct in drivers/video/fbdev/core/fbmem.c that contains the handler functions for the open/read/write/ioctl from user-space (see code below). Some of those handler functions may call subsequently call the fb_ops functions from your driver (see do_fb_ioctl function).
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
...
};
static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct fb_info *info = file_fb_info(file);
if (!info)
return -ENODEV;
return do_fb_ioctl(info, cmd, arg);
}
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
struct fb_ops *fb;
...
switch (cmd) {
case FBIOGET_VSCREENINFO:
...
case FBIOPUT_VSCREENINFO:
...
case FBIOGET_FSCREENINFO:
...
case FBIOPAN_DISPLAY:
...
default:
if (!lock_fb_info(info))
return -ENODEV;
fb = info->fbops;
if (fb->fb_ioctl)
ret = fb->fb_ioctl(info, cmd, arg);
else
ret = -ENOTTY;
unlock_fb_info(info);
}
return ret;
}
In other cases, fb_ops functions may be used by drivers like fbcon that work on top of fbdev. Here is an example of fb_fillrect being called directly by a framebuffer console driver http://lxr.free-electrons.com/source/drivers/video/console/fbcon_cw.c#L80.
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
...
info->fbops->fb_fillrect(info, &region);
}

sending various scsi commands through a single function

I have been playing around with scsi command and I can send some basic commands like different inquirys and such.
I have been using this example to to generate my inquiry. I am working on making this example work with different scsi commands.
http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/pexample.html
I have changed to function to accept different scsi commands through a struct and it also returns a struct based on the output. This works with an inquiry flawlessly. However if I send a READ CAPACITY(16) command the function triggers on the if statement:
(io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
I am new to scsi programming so I might be doing something totally wrong...
my READ CAPACITY(16) command is just this:
scsi_read_capacity.cmdblk[0]=0x9e;
scsi_read_capacity.cmdblk[13]=32;
the rest of the CDB are 0!
here is the code:
#include <stdio.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>
/* global struct to store return data from a scsi cmd*/
typedef struct SCSI_data {
unsigned char data[1024];
unsigned char raw_sens[252];
unsigned char sense_key;
unsigned char additional_sense_code;
unsigned char additional_sense_qualifier;
unsigned char additional_sense_length;
unsigned char sense_data_descriptors[10][244];
int result;
} SCSI_data;
/* global struct to store return data from a scsi cmd*/
typedef struct SCSI_cmd {
int sg_fd;
unsigned char cmdblk[32];
int cmdblklength;
int allocation_length;
int xfer;
int timeout;
} SCSI_cmd;
SCSI_data send_scsicmd(SCSI_cmd cmdobject) {
int k;;
unsigned char inqBuff[cmdobject.allocation_length];
unsigned char sense_buffer[252];
SCSI_data output_data;
sg_io_hdr_t io_hdr;
/* Prepare INQUIRY command */
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = cmdobject.cmdblklength;
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = cmdobject.xfer;
io_hdr.dxfer_len = cmdobject.allocation_length;
io_hdr.dxferp = inqBuff;
io_hdr.cmdp = cmdobject.cmdblk;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = cmdobject.timeout;
if (ioctl(cmdobject.sg_fd, SG_IO, &io_hdr) < 0) {
output_data.result=2;
return output_data;
}
/* now for the error processing */
if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
output_data.result=1;
if (io_hdr.sb_len_wr > 0) {
printf("INQUIRY sense data: ");
for (k = 0; k < io_hdr.sb_len_wr; ++k) {
if ((k > 0) && (0 == (k % 10)))
printf("\n ");
printf("0x%02x ", sense_buffer[k]);
}
printf("\n");
}
if (io_hdr.masked_status)
printf("INQUIRY SCSI status=0x%x\n", io_hdr.status);
if (io_hdr.host_status)
printf("INQUIRY host_status=0x%x\n", io_hdr.host_status);
if (io_hdr.driver_status)
printf("INQUIRY driver_status=0x%x\n", io_hdr.driver_status);
}
else { /* assume INQUIRY response is present */
output_data.result=0;
for (k=0;k<cmdobject.allocation_length;k++) {
output_data.data[k]=inqBuff[k];
}
}
return output_data;
}
int main(int argc, char * argv[]) {
FILE *driveptr=fopen(argv[1], "r");
int i;
SCSI_data scsi_data_read_capacity;
SCSI_cmd scsi_read_capacity;
scsi_read_capacity.sg_fd=fileno(driveptr);
scsi_read_capacity.cmdblk[0]=0x9e;
scsi_read_capacity.cmdblk[13]=32;
scsi_read_capacity.cmdblklength=16;
scsi_read_capacity.xfer=SG_DXFER_FROM_DEV;
scsi_read_capacity.allocation_length=32;
scsi_read_capacity.timeout=1000;
scsi_data_read_capacity=send_scsicmd(scsi_read_capacity);
if (scsi_data_read_capacity.result==0) {
printf(" capacity in blocks: %02x%02x%02x%02x%02x%02x%02x%02x\n",
scsi_data_read_capacity.data[0],
scsi_data_read_capacity.data[1],
scsi_data_read_capacity.data[2],
scsi_data_read_capacity.data[3],
scsi_data_read_capacity.data[4],
scsi_data_read_capacity.data[5],
scsi_data_read_capacity.data[6],
scsi_data_read_capacity.data[7]);
printf(" blocksize: %02x%02x%02x%02x\n",
scsi_data_read_capacity.data[8],
scsi_data_read_capacity.data[9],
scsi_data_read_capacity.data[10],
scsi_data_read_capacity.data[11]);
}
fclose(driveptr);
return 0;
}
I had just a small problem. My CDB was wrong!
I had to use this:
scsi_read_capacity.cmdblk[0]=0x9E;
scsi_read_capacity.cmdblk[1]=0x10;
scsi_read_capacity.cmdblk[13]=32;
the second byte had to be equal to 0x10, this is because the scsi cmd 0x9E is a service action command which accepts an argument in the second byte which defines its behavior!

how to stop linux framebuffer to clear automatically while drawing multiple frames

I am writing a gif decoder, This image is an animated image.When I write the first frame, it displays fine. When, I display the second frame, it displays only the changed pixels. Other pixels are automatically changed to black. I don't know why?.
My first frame has the complete picture.
The second frame has again only the pixel changed and it contains the rest of the unchanged pixels.
Now, when I draw the second buffer, it redraws the unchanged pixels also. And the unchanged pixels are drawn as black ( or precisely in monitor I see these unchanged pixels are absent). That's when it has to draw the second frame.It draws the changed pixels( which is correct), but it re-draws the unchanged pixel as well. And this unchanged pixel are seen as a black ( that is no color). I feel it is a refreshing issue. Or It could be something else. Help is appreciated.
Required: It should redraw the complete image.
In short, this is the snippet of my function.
Unfortunately, it clears off the previous display - linux framebuffer.
I want to stop clearning the linux framebuffer.
here is the complete file.
/** This is using the Direct Fb calls here; and is tightly coupled with Linux Framebuffer **/
static int fbfd = 0;
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
static long int screensize = 0;
static char *fbp = 0;
static int x = 0, y = 0;
static long int location = 0;
/** This is a clone to linux Frame buffer, and will be called to dump on Framebuffer **/
char *local_display_mem;
/** local functions **/
static void SetBackground(FrameData *tempInfo);
static void SetPixel(char *fbp, unsigned int x, unsigned int y, Byte red, Byte green, Byte blue);
/** This is the entry function to initialize the display **/
void display_init()
{
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (fbfd == -1)
{
perror("cannot open framebuffer device");
exit(1);
}
#ifdef DEBUG
printf("The framebuffer device was opened successfully.\n");
#endif
/** Read the Screen Information **/
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1)
{
perror("Driver error-- reading fixed information");
exit(1);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1)
{
perror("Error reading variable information");
exit(1);
}
#ifdef DEBUG
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
#endif
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
local_display_mem = (char*)malloc(screensize);
if ((int)fbp == -1)
{
perror("Error: mmap failed\r\n");
exit(1);
}
#ifdef DEBUG
printf("The framebuffer device was mapped to memory successfully.\n");
#endif
printf("Shreyas..Display Initialized..\r\n");
//munmap(fbp, screensize);
//close(fbfd);
}
/** This function is called by gif_read to display the Image **/
void Display(FrameData *FrameInfo)
{
short int ImageStartX = 0;
short int ImageStartY = 0;
int Index = 0;
printf("\r\n INFO: Display Called.\r\n");
while(1)
{
Index = 0;
ImageStartX = (FrameInfo->frameScreenInfo.LeftPosition);
ImageStartY = (FrameInfo->frameScreenInfo.TopPosition);
while(ImageStartY < ((FrameInfo->frameScreenInfo.ImageHeight)+(FrameInfo->frameScreenInfo.TopPosition)))
{
while(ImageStartX < ((FrameInfo->frameScreenInfo.ImageWidth)+(FrameInfo->frameScreenInfo.LeftPosition)))
{
if(FrameInfo->frame[Index] != FrameInfo->transperencyindex)
{
SetPixel(local_display_mem,ImageStartX,ImageStartY,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Red,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Green,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Blue);
}
Index++;
ImageStartX++;
}
ImageStartY++;
ImageStartX=(FrameInfo->frameScreenInfo.LeftPosition);
}
printf("INFO:..Dumping Framebuffer\r\n");
memcpy(fbp,local_display_mem,screensize);
/** Tune this multiplication to meet the right output on the display **/
usleep((FrameInfo->InterFrameDelay)*100000);
if( FrameInfo->DisposalMethod == 2)
{
printf("set the Background\r\n");
SetBackground(FrameInfo);
}
FrameInfo = FrameInfo->Next;
}
}
static void SetBackground(FrameData *tempInfo)
{
unsigned int ImageStartX=0;
unsigned int ImageStartY=0;
ImageStartX=(tempInfo->frameScreenInfo.LeftPosition);
ImageStartY=(tempInfo->frameScreenInfo.TopPosition);
while(ImageStartY<(tempInfo->frameScreenInfo.ImageHeight))
{
while(ImageStartX<(tempInfo->frameScreenInfo.ImageWidth))
{
SetPixel(local_display_mem,ImageStartX,ImageStartY,255,255,255);
ImageStartX++;
}
ImageStartX=(tempInfo->frameScreenInfo.LeftPosition);
ImageStartY++;
}
}
static void SetPixel(char *fbp_lc, unsigned int x, unsigned int y, Byte red, Byte green, Byte blue)
{
//printf("Shreyas..set pixel called\r\n");
location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
(y+vinfo.yoffset) * finfo.line_length;
if (vinfo.bits_per_pixel == 32)
{
*(fbp_lc + location) = blue; // Some blue
*(fbp_lc + location + 1) = green; // A little green
*(fbp_lc + location + 2) = red; // A lot of red
*(fbp_lc + location + 3) = 0; // No transparency
//location += 4;
}
else
{ //assume 16bpp
unsigned short int t = red<<11 | green << 5 | blue;
*((unsigned short int*)(fbp_lc + location)) = t;
}
//printf("Shreyas..set pixel exit called\r\n");
}
/** This is windows version of display function, and it works correctly.
void Display(FrameData *FrameInfo)
{
short int ImageStartX=0;
short int ImageStartY=0;
int Index=0;
DisplayCntrl=GetDC(hWnd);
printf("Shreyas.. Display Init is called\r\n");
//display_init();
while(1)
{
Index=0;
ImageStartX=(FrameInfo->frameScreenInfo.LeftPosition);
ImageStartY=(FrameInfo->frameScreenInfo.TopPosition);
while(ImageStartY<((FrameInfo->frameScreenInfo.ImageHeight)+(FrameInfo->frameScreenInfo.TopPosition)))
{
while(ImageStartX<((FrameInfo->frameScreenInfo.ImageWidth)+(FrameInfo->frameScreenInfo.LeftPosition)))
{
if(FrameInfo->frame[Index]!=FrameInfo->transperencyindex)
SetPixel(DisplayCntrl,ImageStartX,ImageStartY,RGB(((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Red,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Green,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Blue));
Index++;
ImageStartX++;
}
ImageStartY++;
ImageStartX=(FrameInfo->frameScreenInfo.LeftPosition);
}
Sleep((FrameInfo->InterFrameDelay*10));
WaitForSingleObject(hWnd,10);
if( FrameInfo->DisposalMethod==2)
{
SETBACKGROUND(FrameInfo);
}
FrameInfo=FrameInfo->Next;
}
}
This is the windows version of the same code.
extern hWnd;
HDC DisplayCntrl;
void SETBACKGROUND(FrameData *tempInfo)
{
unsigned int ImageStartX=0;
unsigned int ImageStartY=0;
ImageStartX=(tempInfo->frameScreenInfo.LeftPosition);
ImageStartY=(tempInfo->frameScreenInfo.TopPosition);
while(ImageStartY<(tempInfo->frameScreenInfo.ImageHeight))
{
while(ImageStartX<(tempInfo->frameScreenInfo.ImageWidth))
{
SetPixel(DisplayCntrl,ImageStartX,ImageStartY,RGB(255,255,255));
ImageStartX++;
}
ImageStartX=(tempInfo->frameScreenInfo.LeftPosition);
ImageStartY++;
}
}
void Display(FrameData *FrameInfo)
{
short int ImageStartX=0;
short int ImageStartY=0;
int Index=0;
DisplayCntrl=GetDC(hWnd);
printf("the size of short int is %d",sizeof(short int));
while(1)
{
Index=0;
ImageStartX=(FrameInfo->frameScreenInfo.LeftPosition);
ImageStartY=(FrameInfo->frameScreenInfo.TopPosition);
while(ImageStartY<((FrameInfo->frameScreenInfo.ImageHeight)+(FrameInfo->frameScreenInfo.TopPosition)))
{
while(ImageStartX<((FrameInfo->frameScreenInfo.ImageWidth)+(FrameInfo->frameScreenInfo.LeftPosition)))
{
if(FrameInfo->frame[Index]!=FrameInfo->transperencyindex)
{
SetPixel(DisplayCntrl,ImageStartX,ImageStartY,RGB(((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Red,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Green,((FrameInfo->CMAP)+(FrameInfo->frame[Index]))->Blue));
}
Index++;
ImageStartX++;
}
ImageStartY++;
ImageStartX=(FrameInfo->frameScreenInfo.LeftPosition);
}
Sleep((FrameInfo->InterFrameDelay*10));
WaitForSingleObject(hWnd,10);
if( FrameInfo->DisposalMethod==2)
{
SETBACKGROUND(FrameInfo);
}
FrameInfo=FrameInfo->Next;
}
}
Since you use a local memory buffer local_display_mem, it doesn't matter if somebody would clear the framebuffer - the memcpy will overwrite every pixel.
This means that the condition FrameInfo->frame[Index] != FrameInfo->transperencyindex is always true for some reason since that would cause the algorithm to set each pixel again instead of only updating the changed pixels.

Resources