📄 cpia.c
字号:
/* * USB CPiA Video Camera driver * * Supports CPiA based Video Cameras. Many manufacturers use this chipset. * There's a good chance, if you have a USB video camera, it's a CPiA based * one. * * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/list.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/smp_lock.h>#include <linux/videodev.h>#include <linux/vmalloc.h>#include <linux/wrapper.h>#include <linux/module.h>#include <linux/spinlock.h>#include <asm/io.h>#include "usb.h"#include "cpia.h"static int debug = 0;MODULE_PARM(debug, "i");/* Video Size 384 x 288 x 3 bytes for RGB *//* 384 because xawtv tries to grab 384 even though we tell it 352 is our max */#define MAX_FRAME_SIZE (384 * 288 * 3)/*******************************//* Memory management functions *//*******************************/#define MDEBUG(x) do { } while(0) /* Debug memory management */static struct usb_driver cpia_driver;/* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){ unsigned long ret = 0UL; pmd_t *pmd; pte_t *ptep, pte; if (!pgd_none(*pgd)) { pmd = pmd_offset(pgd, adr); if (!pmd_none(*pmd)) { ptep = pte_offset(pmd, adr); pte = *ptep; if (pte_present(pte)) ret = page_address(pte_page(pte)) | (adr & (PAGE_SIZE-1)); } } MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); return ret;}static inline unsigned long uvirt_to_bus(unsigned long adr){ unsigned long kva, ret; kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); ret = virt_to_bus((void *)kva); MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); return ret;}static inline unsigned long kvirt_to_bus(unsigned long adr){ unsigned long va, kva, ret; va = VMALLOC_VMADDR(adr); kva = uvirt_to_kva(pgd_offset_k(va), va); ret = virt_to_bus((void *)kva); MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); return ret;}/* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */static inline unsigned long kvirt_to_pa(unsigned long adr){ unsigned long va, kva, ret; va = VMALLOC_VMADDR(adr); kva = uvirt_to_kva(pgd_offset_k(va), va); ret = __pa(kva); MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); return ret;}static void *rvmalloc(unsigned long size){ void *mem; unsigned long adr, page; /* Round it off to PAGE_SIZE */ size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); mem = vmalloc(size); if (!mem) return NULL; memset(mem, 0, size); /* Clear the ram out, no junk to the user */ adr = (unsigned long) mem; while (size > 0) { page = kvirt_to_pa(adr); mem_map_reserve(MAP_NR(__va(page))); adr += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } return mem;}static void rvfree(void *mem, unsigned long size){ unsigned long adr, page; if (!mem) return; size += (PAGE_SIZE - 1); size &= ~(PAGE_SIZE - 1); adr=(unsigned long) mem; while (size > 0) { page = kvirt_to_pa(adr); mem_map_unreserve(MAP_NR(__va(page))); adr += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } vfree(mem);}static int usb_cpia_get_version(struct usb_device *dev, void *buf){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_CPIA_GET_VERSION, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, buf, 4, HZ);}#ifdef NOTUSEDstatic int usb_cpia_get_pnp_id(struct usb_device *dev, void *buf){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_CPIA_GET_PNP_ID, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, buf, 6, HZ);}#endif#ifdef NOTUSEDstatic int usb_cpia_get_camera_status(struct usb_device *dev, void *buf){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_CPIA_GET_CAMERA_STATUS, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, buf, 8, HZ);}#endifstatic int usb_cpia_goto_hi_power(struct usb_device *dev){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_GOTO_HI_POWER, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);}static int usb_cpia_get_vp_version(struct usb_device *dev, void *buf){ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_CPIA_GET_VP_VERSION, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, buf, 4, HZ);}static int usb_cpia_set_sensor_fps(struct usb_device *dev, int sensorbaserate, int sensorclkdivisor){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_SENSOR_FPS, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (sensorbaserate << 8) + sensorclkdivisor, 0, NULL, 0, HZ);}#ifdef NOTUSEDstatic int usb_cpia_grab_frame(struct usb_device *dev, int streamstartline){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_GRAB_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE, streamstartline << 8, 0, NULL, 0, HZ);}#endifstatic int usb_cpia_upload_frame(struct usb_device *dev, int forceupload){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_UPLOAD_FRAME, USB_TYPE_VENDOR | USB_RECIP_DEVICE, forceupload, 0, NULL, 0, HZ);}static int usb_cpia_set_grab_mode(struct usb_device *dev, int continuousgrab){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_GRAB_MODE, USB_TYPE_VENDOR | USB_RECIP_DEVICE, continuousgrab, 0, NULL, 0, HZ);}static int usb_cpia_set_format(struct usb_device *dev, int size, int subsample, int order){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_FORMAT, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (subsample << 8) + size, order, NULL, 0, HZ);}static int usb_cpia_set_roi(struct usb_device *dev, int colstart, int colend, int rowstart, int rowend){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_ROI, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (colend << 8) + colstart, (rowend << 8) + rowstart, NULL, 0, HZ);}static int usb_cpia_set_compression(struct usb_device *dev, int compmode, int decimation){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_COMPRESSION, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (decimation << 8) + compmode, 0, NULL, 0, HZ);}#ifdef NOTUSEDstatic int usb_cpia_set_compression_target(struct usb_device *dev, int target, int targetfr, int targetq){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_SET_COMPRESSION_TARGET, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (targetfr << 8) + target, targetq, NULL, 0, HZ);}#endif#ifdef NOTUSEDstatic int usb_cpia_initstreamcap(struct usb_device *dev, int skipframes, int streamstartline){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_INIT_STREAM_CAP, USB_TYPE_VENDOR | USB_RECIP_DEVICE, (streamstartline << 8) + skipframes, 0, NULL, 0, HZ);}static int usb_cpia_finistreamcap(struct usb_device *dev){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_FINI_STREAM_CAP, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);}static int usb_cpia_startstreamcap(struct usb_device *dev){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_START_STREAM_CAP, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);}static int usb_cpia_endstreamcap(struct usb_device *dev){ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), USB_REQ_CPIA_END_STREAM_CAP, USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, NULL, 0, HZ);}#endif/* How much data is left in the scratch buf? */#define scratch_left(x) (cpia->scratchlen - (int)((char *)x - (char *)cpia->scratch))static void cpia_parse_data(struct usb_cpia *cpia){ struct cpia_frame *frame, *pframe; unsigned char *data = cpia->scratch; unsigned long left; long copylen = 0; /* Grab the current frame and the previous frame */ frame = &cpia->frame[cpia->curframe]; pframe = &cpia->frame[(cpia->curframe - 1 + CPIA_NUMFRAMES) % CPIA_NUMFRAMES]; while (1) { if (!scratch_left(data)) goto out; switch (frame->scanstate) { case STATE_SCANNING: { struct cpia_frame_header *header; /* We need at least 2 bytes for the magic value */ if (scratch_left(data) < 2) goto out; header = (struct cpia_frame_header *)data; if (be16_to_cpup(&header->magic) == CPIA_MAGIC) { frame->scanstate = STATE_HEADER; break; } /* Woops, lost the header, find the end of the frame */ if (scratch_left(data) < 4) goto out; /* See if we found the end of the frame */ while (scratch_left(data) >= 4) { if (*((__u32 *)data) == 0xFFFFFFFF) { data += 4; if (debug >= 1) printk(KERN_INFO "cpia: EOF while scanning for magic\n"); goto error; } data++; } break; } case STATE_HEADER: /* We need at least 64 bytes for the header */ if (scratch_left(data) < sizeof(struct cpia_frame_header)) goto out; memcpy(&frame->header, data, sizeof(struct cpia_frame_header)); /* Skip over the header */ data += sizeof(struct cpia_frame_header); frame->hdrwidth = (frame->header.col_end - frame->header.col_start) * 8; frame->hdrheight = (frame->header.row_end - frame->header.row_start) * 4; if (debug >= 2) { printk(KERN_DEBUG "cpia: frame size %dx%d\n", frame->hdrwidth, frame->hdrheight); printk(KERN_DEBUG "cpia: frame %scompressed\n", frame->header.comp_enable ? "" : "not "); } frame->scanstate = STATE_LINES; frame->curline = 0; break; case STATE_LINES: { unsigned char *f, *end; unsigned int len; int i; int y, u, y1, v, r, g, b; /* We want at least 2 bytes for the length */ if (scratch_left(data) < 2) goto out; /* Grab the length */ len = data[0] + (data[1] << 8); /* Check to make sure it's nothing outrageous */ if (len > (frame->hdrwidth * 2) + 1) { if (debug >= 1) printk(KERN_DEBUG "cpia: bad length, resynching (expected %d, got %d)\n", (frame->hdrwidth * 2) + 1, len); goto error; } /* Make sure there's enough data for the entire line */ if (scratch_left(data + 2) < len) goto out; /* Skip over the length */ data += 2; /* Is the end of the line there */ if (data[len - 1] != 0xFD) { if (debug >= 1) printk(KERN_DEBUG "cpia: lost synch\n"); goto error; } /* Start at the beginning */ end = data + len - 1; f = frame->data + (frame->width * 3 * frame->curline); if (frame->header.comp_enable) { unsigned char *fp; /* We use the previous frame as a reference */ fp = pframe->data + (frame->width * 3 * frame->curline); while (data < end) { if (*data & 1) { /* Compress RLE data */ i = *data >> 1; memcpy(f, fp, i * 3); copylen += (i * 3); f += (i * 3); fp += (i * 3); data++; } else { /* Raw data */#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)y = *data++ - 16;u = *data++ - 128;y1 = *data++ - 16;v = *data++ - 128;r = 104635 * v;g = -25690 * u + -53294 * v;b = 132278 * u;y *= 76310;y1 *= 76310;*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);*f++ = LIMIT(b + y1); *f++ = LIMIT(g + y1); *f++ = LIMIT(r + y1); fp += 6; copylen += 6; } } } else { /* Raw data */ while (data < end) {y = *data++ - 16;u = *data++ - 128;y1 = *data++ - 16;v = *data++ - 128;r = 104635 * v;g = -25690 * u + -53294 * v;b = 132278 * u;y *= 76310;y1 *= 76310;*f++ = LIMIT(b + y); *f++ = LIMIT(g + y); *f++ = LIMIT(r + y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -