- 论坛徽章:
- 0
|
2. Read功能:
完成数据的读取,其主要的工作就是将数据由内核空间传送到进程用户空间。
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)) //获取信号量
return -EINTR;
if (!dev || !buf){ //判断设备情况
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, //在指定的队列上睡眠,直到参数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++) //当数据到来
if (spca50x->frame.grabstate == FRAME_DONE) //标识数据已到
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))) //实现用户空间和内核空间的数据拷贝
{
PDEBUG (2, "Copy failed! %d bytes not copied", i);
up(&spca50x->lock);
return -EFAULT;
}
/* Release the frame */
frame->grabstate = FRAME_READY; //标识数据已空
up(&spca50x->lock);
return count; //返回拷贝的数据数
}
3. Mmap功能:
实现将设备内存映射到用户进程的地址空间的功能,其关键函数是remap_page_range,其具体实现如下:
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)) //获取信号量
return -EINTR;
pos = (unsigned long) spca50x->fbuf;
while (size > 0) //循环实现内存映射
{
page = kvirt_to_pa (pos);
if (remap_page_range (start, page, PAGE_SIZE, PAGE_SHARED)){ //实现内存映射
up(&spca50x->lock);
return -EAGAIN; }
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
size -= PAGE_SIZE;
else
size = 0;
}
up(&spca50x->lock); //释放信号量
return 0;
}
4. Ioctl功能:
实现文件信息的获取功能,
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)) //获取信号量
return -EINTR;
rc = video_usercopy (inode, file, cmd, arg, spca5xx_do_ioctl); //将信息传送到用户进程,其关键函数实现spca5xx_do_ioctl
up(&spca50x->lock);
return rc;
}
spca5xx_do_ioctl函数的实现依赖于不同的硬件,本驱动为了支持多种芯片,实现程序过于烦琐,其主要思想是通过copy_to_user(arg,b,sizeof(struct video_capability)函数将设备信息传递给用户进程。
三.数据传输模块:
源程序采用tasklet来实现同步快速传递数据,并通过spcadecode.c上的软件解码模块实现图形信息的解码。此模块的入口点挂节在spca_open函数中,其具体的函数为spca50x_init_isoc。当设备被打开时,同步传输数据也已经开始,并通过spca50x_move_data函数将数据传递给驱动程序,驱动程序通过轮询的办法实现对数据的访问。
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); //输出处理过的图片数据
if (err != 0)
{
PDEBUG (0, "frame decoder failed (%d)", err);
taskletframe->grabstate = FRAME_ERROR;
}
else
{
taskletframe->grabstate = FRAME_DONE;
}
if (waitqueue_active (&taskletframe->wq)) //如果有进程等待,唤醒等待进程
wake_up_interruptible (&taskletframe->wq);
}
值得一提的是spcadecode.c上解码模块将原始压缩图形数据流yyuyv,yuvy, jpeg411,jpeg422解码为RGB图形,但此部分解压缩算法的实现也依赖于压缩的格式,归根结底依赖于DSP(数字处理芯片)中的硬件压缩算法。
四.USB CORE的支持:
LINUX下的USB设备对下层硬件的操作依靠系统实现的USB CORE层,USB CORE对上层驱动提供了众多函数接口如:usb_control_msg,usb_sndctrlpipe等,其中最典型的使用为源码中对USB端点寄存器的读写函数spca50x_reg_write和spca50x_reg_read等,具体实现如下:(举spca50x_reg_write的实现,其他类似)
static int spca50x_reg_write(struct usb_device *dev,__u16 reg,__u16 index,
__u16 value)
{
int rc;
rc = usb_control_msg(dev, //通过USB CORE提供的接口函数设置寄存器的值
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;
}
以上为驱动程序的具体框架说明,以及其中的关键数据结构和函数说明。 |
|