- 論壇徽章:
- 0
|
2. Read功能:
完成數(shù)據(jù)的讀取,其主要的工作就是將數(shù)據(jù)由內(nèi)核空間傳送到進(jìn)程用戶空間。
static long
spca5xx_read(struct video_device *dev, char * buf, unsigned long
count,int noblock)
{
struct usb_spca50x *spca50x = video_get_drvdata (dev);
int i;
int frmx = -1;
int rc;
volatile struct spca50x_frame *frame;
if (down_interruptible(&spca50x->lock)) //獲取信號(hào)量
return -EINTR;
if (!dev || !buf){ //判斷設(shè)備情況
up(&spca50x->lock);
return -EFAULT;
}
if (!spca50x->dev){
up(&spca50x->lock);
return -EIO;
}
if (!spca50x->streaming){
up(&spca50x->lock);
return -EIO;
}
if((rc = wait_event_interruptible(spca50x->wq, //在指定的隊(duì)列上睡眠,直到參數(shù)2的條件為真
spca50x->frame[0].grabstate == FRAME_DONE ||
spca50x->frame[1].grabstate == FRAME_DONE ||
spca50x->frame[2].grabstate == FRAME_DONE ||
spca50x->frame[3].grabstate == FRAME_DONE ))){
up(&spca50x->lock);
return rc;
}
for (i = 0; i < SPCA50X_NUMFRAMES; i++) //當(dāng)數(shù)據(jù)到來
if (spca50x->frame.grabstate == FRAME_DONE) //標(biāo)識(shí)數(shù)據(jù)已到
frmx = i;
if (frmx < 0)
{
PDEBUG (2, "Couldnt find a frame ready to be read.");
up(&spca50x->lock);
return -EFAULT;
}
frame = &spca50x->frame[frmx];
PDEBUG (2, "count asked: %d available: %d", (int) count,
(int) frame->scanlength);
if (count > frame->scanlength)
count = frame->scanlength;
if ((i = copy_to_user (buf, frame->data, count))) //實(shí)現(xiàn)用戶空間和內(nèi)核空間的數(shù)據(jù)拷貝
{
PDEBUG (2, "Copy failed! %d bytes not copied", i);
up(&spca50x->lock);
return -EFAULT;
}
/* Release the frame */
frame->grabstate = FRAME_READY; //標(biāo)識(shí)數(shù)據(jù)已空
up(&spca50x->lock);
return count; //返回拷貝的數(shù)據(jù)數(shù)
}
3. Mmap功能:
實(shí)現(xiàn)將設(shè)備內(nèi)存映射到用戶進(jìn)程的地址空間的功能,其關(guān)鍵函數(shù)是remap_page_range,其具體實(shí)現(xiàn)如下:
static int
spca5xx_mmap(struct video_device *dev,const char *adr, unsigned long size)
{
unsigned long start=(unsigned long) adr;
struct usb_spca50x *spca50x = dev->priv;
unsigned long page, pos;
if (spca50x->dev == NULL)
return -EIO;
PDEBUG (4, "mmap: %ld (%lX) bytes", size, size);
if (size >
(((SPCA50X_NUMFRAMES * MAX_DATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE -1)))
return -EINVAL;
if (down_interruptible(&spca50x->lock)) //獲取信號(hào)量
return -EINTR;
pos = (unsigned long) spca50x->fbuf;
while (size > 0) //循環(huán)實(shí)現(xiàn)內(nèi)存映射
{
page = kvirt_to_pa (pos);
if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){ //實(shí)現(xiàn)內(nèi)存映射
up(&spca50x->lock);
return -EAGAIN; }
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
size -= PAGE_SIZE;
else
size = 0;
}
up(&spca50x->lock); //釋放信號(hào)量
return 0;
}
4. Ioctl功能:
實(shí)現(xiàn)文件信息的獲取功能,
static int
spca5xx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = file->private_data;
struct usb_spca50x *spca50x = vdev->priv;
int rc;
if (down_interruptible(&spca50x->lock)) //獲取信號(hào)量
return -EINTR;
rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl); //將信息傳送到用戶進(jìn)程,其關(guān)鍵函數(shù)實(shí)現(xiàn)spca5xx_do_ioctl
up(&spca50x->lock);
return rc;
}
spca5xx_do_ioctl函數(shù)的實(shí)現(xiàn)依賴于不同的硬件,本驅(qū)動(dòng)為了支持多種芯片,實(shí)現(xiàn)程序過于煩瑣,其主要思想是通過copy_to_user(arg,b,sizeof(struct video_capability)函數(shù)將設(shè)備信息傳遞給用戶進(jìn)程。
三.?dāng)?shù)據(jù)傳輸模塊:
源程序采用tasklet來實(shí)現(xiàn)同步快速傳遞數(shù)據(jù),并通過spcadecode.c上的軟件解碼模塊實(shí)現(xiàn)圖形信息的解碼。此模塊的入口點(diǎn)掛節(jié)在spca_open函數(shù)中,其具體的函數(shù)為spca50x_init_isoc。當(dāng)設(shè)備被打開時(shí),同步傳輸數(shù)據(jù)也已經(jīng)開始,并通過spca50x_move_data函數(shù)將數(shù)據(jù)傳遞給驅(qū)動(dòng)程序,驅(qū)動(dòng)程序通過輪詢的辦法實(shí)現(xiàn)對(duì)數(shù)據(jù)的訪問。
void
outpict_do_tasklet (unsigned long ptr)
{
int err;
struct spca50x_frame *taskletframe = (struct spca50x_frame *) ptr;
taskletframe->scanlength = taskletframe->highwater - taskletframe->data;
PDEBUG (2, "Tasklet ask spcadecoder hdrwidth %d hdrheight %d method %d",
taskletframe->hdrwidth, taskletframe->hdrheight,
taskletframe->method);
err = spca50x_outpicture (taskletframe); //輸出處理過的圖片數(shù)據(jù)
if (err != 0)
{
PDEBUG (0, "frame decoder failed (%d)", err);
taskletframe->grabstate = FRAME_ERROR;
}
else
{
taskletframe->grabstate = FRAME_DONE;
}
if (waitqueue_active (&taskletframe->wq)) //如果有進(jìn)程等待,喚醒等待進(jìn)程
wake_up_interruptible (&taskletframe->wq);
}
值得一提的是spcadecode.c上解碼模塊將原始?jí)嚎s圖形數(shù)據(jù)流yyuyv,yuvy, jpeg411,jpeg422解碼為RGB圖形,但此部分解壓縮算法的實(shí)現(xiàn)也依賴于壓縮的格式,歸根結(jié)底依賴于DSP(數(shù)字處理芯片)中的硬件壓縮算法。
四.USB CORE的支持:
LINUX下的USB設(shè)備對(duì)下層硬件的操作依靠系統(tǒng)實(shí)現(xiàn)的USB CORE層,USB CORE對(duì)上層驅(qū)動(dòng)提供了眾多函數(shù)接口如:usb_control_msg,usb_sndctrlpipe等,其中最典型的使用為源碼中對(duì)USB端點(diǎn)寄存器的讀寫函數(shù)spca50x_reg_write和spca50x_reg_read等,具體實(shí)現(xiàn)如下:(舉spca50x_reg_write的實(shí)現(xiàn),其他類似)
static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,
__u16 value)
{
int rc;
rc = usb_control_msg(dev, //通過USB CORE提供的接口函數(shù)設(shè)置寄存器的值
usb_sndctrlpipe(dev, 0),
reg,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0, TimeOut);
PDEBUG(5, "reg write: 0x%02X,0x%02X:0x%02X, 0x%x", reg, index, value, rc);
if (rc < 0)
err("reg write: error %d", rc);
return rc;
}
以上為驅(qū)動(dòng)程序的具體框架說明,以及其中的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)和函數(shù)說明。 |
|