swarm_saa7114h.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 1,696 行 · 第 1/3 页

C
1,696
字号
	out64(M_DMA_L2CA, MAC2_DMARX0_CSR(R_MAC_DMA_CONFIG1));	out64(d->ff.descrtab_phys, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_BASE));	/* Enable interrupts and DMA */	out64(M_MAC_INT_EOP_COUNT<<S_MAC_RX_CH0, MAC2_CSR(R_MAC_INT_MASK));	out64(M_MAC_RXDMA_EN0 | M_MAC_BYP_RX_ENABLE, MAC2_CSR(R_MAC_ENABLE));	return 0;}/* ----------------------------------------------------------------------- * v4linux helpers - color conversion, etc  (taken from cpia.c) * ----------------------------------------------------------------------- */#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)static void yuvconvert_inplace(uint8_t *data, uint32_t in_uyvy, int out_fmt, int mmap){	int y, u, v, r, g, b, y1;	uint8_t *src, *dst;	if (out_fmt == VIDEO_PALETTE_RGB24) {		src = (uint8_t *)((int)data + in_uyvy);		dst = (uint8_t *)((int)data + in_uyvy + (in_uyvy >> 1));		DBG(DBG_CONVERT, printk(KERN_DEBUG "inplace: %p %p %p\n", data, src, dst));		while (src > data) {			if ((int)(src-data) < 4)				break;				//printk("freaky %p %p\n", src, data);			y1 = (*(--src) - 16) * 76310;			v = *(--src) - 128;			y = (*(--src) - 16) * 76310;			u = *(--src) - 128;			r = 104635 * v;			g = -25690 * u + -53294 * v;			b = 132278 * u;			/* XXXKW what on earth is up with mmap? */			if (mmap) {				*(--dst) = LIMIT(r+y1);				*(--dst) = LIMIT(g+y1);				*(--dst) = LIMIT(b+y1);				*(--dst) = LIMIT(r+y);				*(--dst) = LIMIT(g+y);				*(--dst) = LIMIT(b+y);			} else {				*(--dst) = LIMIT(b+y1);				*(--dst) = LIMIT(g+y1);				*(--dst) = LIMIT(r+y1);				*(--dst) = LIMIT(b+y);				*(--dst) = LIMIT(g+y);				*(--dst) = LIMIT(r+y);			}		}	}}static int saa7114h_get_cparams(struct saa7114h *decoder){	/* XXX check for error code */	decoder->bright	    = saa7114h_reg_read(decoder, SAA_BRIGHTNESS);	decoder->contrast   = saa7114h_reg_read(decoder, SAA_CONTRAST);	decoder->sat	    = saa7114h_reg_read(decoder, SAA_SATURATION);	decoder->hue	    = saa7114h_reg_read(decoder, SAA_HUE);	decoder->vp.brightness = (uint16_t)decoder->bright << 8;	decoder->vp.contrast   = (uint16_t)decoder->contrast << 9;	decoder->vp.colour     = decoder->sat << 9;	decoder->vp.hue	       = ((int16_t)decoder->hue + 128) << 8;	return 0;}static int saa7114h_set_cparams(struct saa7114h *decoder){	decoder->bright	  = decoder->vp.brightness >> 8;	decoder->contrast = decoder->vp.contrast >> 9;	decoder->sat	  = decoder->vp.colour >> 9;	decoder->hue	  = (uint8_t)((int8_t)(decoder->vp.hue >> 8) - 128);	return (saa7114h_reg_write(decoder, SAA_BRIGHTNESS, decoder->bright) ||		saa7114h_reg_write(decoder, SAA_CONTRAST, decoder->contrast) ||		saa7114h_reg_write(decoder, SAA_SATURATION, decoder->sat) ||		saa7114h_reg_write(decoder, SAA_HUE, decoder->hue));}/* ----------------------------------------------------------------------- * Custom IOCTL support * ----------------------------------------------------------------------- */unsigned char eav[625][2];static int grab_frame(struct saa7114h *d, void *user_buf, int print_eav){	int cur_idx = 0;	int to_go = 625;	int delta;	int i, len, eav_val, sav_val;	int started = 0;	uint8_t *buf;	fifo_descr_t *cur_d;	int swptr = d->ff.next_descr - d->ff.descrtab;	int hwptr;	DBG(DBG_CALL, printk(IF_NAME ": grabbing frame\n"));	/* Check for Macrovision -- if it's on, DMA won't happen */	if (saa7114h_reg_read(d, DECODER_STATUS) & 0x2)		return -EACCES;	out64(d->ff.ringsz, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));	do {		hwptr = (unsigned) (((in64(MAC2_DMARX0_CSR(R_MAC_DMA_CUR_DSCRADDR)) &				      M_DMA_CURDSCR_ADDR) -				     d->ff.descrtab_phys) /				    sizeof(fifo_descr_t));		delta = (hwptr + d->ff.ringsz - swptr) % d->ff.ringsz;				if (delta == 0) {#if 0			uint64_t val = in64(MAC2_DMARX0_CSR(R_MAC_STATUS));			printk("mac status: %08x%08x\n",			       (u32)(val >> 32), (u32)(val&0xffffffff));#endif		}		for (i=0; i<delta; i++) {			cur_d = d->ff.next_descr;			if (++d->ff.next_descr == d->ff.descrtab_end)				d->ff.next_descr = d->ff.descrtab;						if (!(cur_d->descr_a & M_DMA_ETHRX_SOP)) {				printk("bogus RX\n");				continue;			}			cur_d->descr_a &= ~M_DMA_ETHRX_SOP;			len = G_DMA_DSCRB_PKT_SIZE(cur_d->descr_b);			buf = (uint8_t *)__va(cur_d->descr_a & M_DMA_DSCRA_A_ADDR);			if (len != (d->vw.width*RAW_PER_PIXEL)+RAW_LINE_PAD) {				printk("funny size %d\n", len);				continue;			}			eav_val = buf[1];			sav_val = buf[5];			if (eav_val == 0xf1) { /* end of field 2, V-blank */				if (started) {					started = 0;					delta = to_go = 0;					/* just let DMA finish in background */				} else {					started = 1;				}			}			if (started) {				eav[cur_idx][0] = eav_val;				eav[cur_idx++][1] = sav_val;				if (copy_to_user(user_buf, &buf[6], 1440))					return -EFAULT;				user_buf += 1440;			}		}		swptr = hwptr;		if (delta) {			if (started)				to_go -= delta;			if (delta > to_go)				delta = to_go;			out64(delta, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));		}	} while (to_go);	if (print_eav) {		for (i=0; i<cur_idx; i++) {			printk("%3d: %02x | %02x\n", i, eav[i][0], eav[i][1]);		}	}	return cur_idx;}/* ----------------------------------------------------------------------- * Interrupt handler * ----------------------------------------------------------------------- */unsigned long int_count = 0;static void saa7114h_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct saa7114h *d = dev_id;	uint64_t status_val;	fifo_descr_t *cur_d;	int i, delta, len;	uint8_t *buf, eav_val;	int swptr = d->ff.next_descr - d->ff.descrtab;	int hwptr;	status_val = in64(MAC2_CSR(R_MAC_STATUS));	/* Process finished decsriptors */	hwptr = (unsigned) (((in64(MAC2_DMARX0_CSR(R_MAC_DMA_CUR_DSCRADDR)) &			      M_DMA_CURDSCR_ADDR) - d->ff.descrtab_phys) /			    sizeof(fifo_descr_t));	delta = (hwptr + d->ff.ringsz - swptr) % d->ff.ringsz;	if (!delta) {		if (status_val & M_MAC_INT_EOP_SEEN<<S_MAC_RX_CH0) {			/* Must have wrapped since the last interrupt */			delta = d->ff.ringsz;		} else {			/* XXXKW why would this happen? */			return;		}	}	for (i=0; i<delta; i++) {		cur_d = d->ff.next_descr;		if (++d->ff.next_descr == d->ff.descrtab_end)			d->ff.next_descr = d->ff.descrtab;				if (!(cur_d->descr_a & M_DMA_ETHRX_SOP)) {			printk(KERN_DEBUG "bogus RX\n");			continue;		}		cur_d->descr_a &= ~M_DMA_ETHRX_SOP;		if (!d->dma_enable)			continue;				len = G_DMA_DSCRB_PKT_SIZE(cur_d->descr_b);		buf = (uint8_t *)__va(cur_d->descr_a & M_DMA_DSCRA_A_ADDR);		if (len != (d->vw.width*RAW_PER_PIXEL)+RAW_LINE_PAD) {			printk(KERN_DEBUG "funny size %d\n", len);//				  continue;		}		len -= RAW_LINE_PAD;		eav_val = buf[1];		DBG(DBG_FRAMING_LOUD,		    printk(KERN_DEBUG "eav: %02x len: %d\n", eav_val, len));		if (eav_val == 0xf1) { /* end of field 2, V-blank: start-of-frame */			switch (d->frame[d->hwframe].state) {			case FRAME_UNUSED:				DBG(DBG_FRAMING,				    printk(KERN_ERR "capture to unused frame %d\n", 					   d->hwframe));				break;			case FRAME_READY:				DBG(DBG_FRAMING,				    printk(KERN_DEBUG "frame started %d\n",					   d->hwframe));				/* start this frame (skip eav/sav) */				memcpy(d->frame[d->hwframe].pos, &buf[6], len);#if DMA_DEINTERLACE				if (!d->interlaced)					memcpy(d->frame[d->hwframe].pos-len, &buf[6], len);				d->frame[d->hwframe].pos += len*2;#else				d->frame[d->hwframe].pos += len;#endif				d->frame[d->hwframe].state = FRAME_GRABBING;				/* XXXKW check pos overflow */				break;			case FRAME_GRABBING:				/* kick over to new frame */				d->frame[d->hwframe].size = d->frame[d->hwframe].pos -					d->frame[d->hwframe].data;				d->frame[d->hwframe].state = FRAME_DONE;				DBG(DBG_FRAMING,				    printk(KERN_DEBUG "frame finished %d\n",					   d->frame[d->hwframe].size));				/* wake up a waiting reader */				DBG(DBG_IO, printk(KERN_DEBUG "wakeup\n"));				wake_up(&d->frame[d->hwframe].read_wait);				d->hwframe = (d->hwframe + 1) % NUM_FRAME;				if (d->frame[d->hwframe].state == FRAME_READY) {					/* start this frame */					DBG(DBG_FRAMING,					    printk(KERN_DEBUG "frame bumped %d\n",						   d->hwframe));					memcpy(d->frame[d->hwframe].pos, &buf[6], len);#if DMA_DEINTERLACE					if (!d->interlaced)						memcpy(d->frame[d->hwframe].pos-len, &buf[6], len);					d->frame[d->hwframe].pos += len*2;#else					d->frame[d->hwframe].pos += len;#endif					d->frame[d->hwframe].state = FRAME_GRABBING;				} else {					/* drop on the floor,					   note that we've stopped DMA'ing */					DBG(DBG_FRAMING,					    printk(KERN_DEBUG "frame capture halted\n"));					d->dma_enable = 0;				}				break;			case FRAME_DONE:				/* drop on the floor (must be waiting for sw) */				DBG(DBG_FRAMING,				    printk(KERN_DEBUG "frame capture halted\n"));				d->dma_enable = 0;				break;			}		} else {			switch (d->frame[d->hwframe].state) {			case FRAME_UNUSED:				DBG(DBG_FRAMING,				    printk(KERN_ERR "capture to unused frame %d\n",					   d->hwframe));				break;			case FRAME_READY:				/* drop on the floor (must have dropped something) */				DBG(DBG_FRAMING_LOUD,				    printk(KERN_DEBUG "missed SOF\n"));				break;			case FRAME_DONE:				/* drop on the floor (must be waiting for sw) */				DBG(DBG_FRAMING,				    printk(KERN_DEBUG "frame overflow\n"));				d->dma_enable = 0;				break;			case FRAME_GRABBING:#if DMA_DEINTERLACE				if (eav_val == 0xb6) {					d->frame[d->hwframe].pos = d->frame[d->hwframe].data;				}				memcpy(d->frame[d->hwframe].pos, &buf[6], len);				if (!d->interlaced)					memcpy(d->frame[d->hwframe].pos-len, &buf[6], len);				d->frame[d->hwframe].pos += len*2;#else				memcpy(d->frame[d->hwframe].pos, &buf[6], len);				d->frame[d->hwframe].pos += len;#endif				/* XXXKW check pos overflow */				break;			}		}	}		if (d->dma_enable) {		out64(delta, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));		DBG(DBG_DESCR,		    printk(KERN_DEBUG IF_NAME ": interrupt adds %d -> %d descrs\n",			   delta, (int)in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT))));	}}/* ----------------------------------------------------------------------- * /dev/video interface * ----------------------------------------------------------------------- */static int saa7114h_open(struct video_device *vd, int nb){	struct saa7114h *d = vd->priv;	uint32_t status;	if (!d || d->opened)		return -EBUSY;	d->opened = 1;	DBG(DBG_CALL, printk(KERN_DEBUG IF_NAME ": open\n"));	/* XXKW Should check this periodically!? */	status = saa7114h_reg_read(d, DECODER_STATUS);	d->interlaced = ((status & 0x80) != 0);#if !NULL_DMA	if (d->dma_enable) {		printk(IF_NAME ": open found DMA on?!\n");#if LAZY_READ	}#else	} else {		int descr;		d->dma_enable = 1;		DBG(DBG_DESCR, printk(IF_NAME ": open enabling DMA\n"));		/* Force capture to start into frame buffer 0 */		descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));		DBG(DBG_DESCR,		    printk(IF_NAME ": open adds %d -> %d descrs\n",			   d->ff.ringsz-desc, descr));		out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));	}#endif#endif	return 0;}static void saa7114h_release(struct video_device *vd){	struct saa7114h *d = vd->priv;	DBG(DBG_CALL, printk(KERN_DEBUG IF_NAME ": release\n"));	d->opened = 0;	d->dma_enable = 0;	/* XXXKW do a clean drain of outstanding DMAs? toss leftover	   buffer contents to avoid stale pictures? */	return;}static long saa7114h_read(struct video_device *vd, char *buf,			  unsigned long count, int noblock){	struct saa7114h *d = vd->priv;	int descr, status;	if (!d)		return -ENODEV;	/* XXKW Should check this periodically!? */	status = saa7114h_reg_read(d, DECODER_STATUS);//	  d->interlaced = ((status & 0x80) != 0);	#if !NULL_DMA#if LAZY_READ	if (!d->dma_enable) {		DBG(DBG_DESCR, printk(KERN_DEBUG IF_NAME ": enabling DMA\n"));		/* Give the buffer to the DMA engine (force ptr reset) */		d->swframe = d->hwframe;		d->frame[d->swframe].state = FRAME_READY;#if DMA_DEINTERLACE		d->frame[d->swframe].pos = d->frame[d->swframe].data+d->vw.width*RAW_PER_PIXEL;#else		d->frame[d->swframe].pos = d->frame[d->swframe].data;#endif		/* Fire up the DMA engine again if it stopped */		d->dma_enable = 1;		descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));		out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));	}#endif#endif	/* XXXKW mmap/read mixture could break the swframe sequence */	if (d->frame[d->swframe].state != FRAME_DONE) {		if (noblock)			return -EAGAIN;		else {			DBG(DBG_IO,			    printk(KERN_DEBUG IF_NAME ": sleeping for frame\n"));			interruptible_sleep_on(&d->frame[d->swframe].read_wait);			DBG(DBG_IO,			    printk(KERN_DEBUG IF_NAME ": awakened\n"));			if (signal_pending(current))				return -ERESTARTSYS;		}	}	if (count < d->frame[d->swframe].size)		return -EFAULT;	count = d->frame[d->swframe].size;	yuvconvert_inplace(d->frame[d->swframe].data, d->frame[d->swframe].size, d->vp.palette, 0);	copy_to_user(buf, d->frame[d->swframe].data, d->frame[d->swframe].size);	d->swframe = (d->swframe + 1) % NUM_FRAME;	/* XXXKW doesn't do format conversion!!! */#if !NULL_DMA#if !LAZY_READ	/* XXXKW Fire up the DMA engine again if it stopped ??? */	if (!d->dma_enable) {		DBG(DBG_DESCR, printk(KERN_DEBUG IF_NAME ": enabling DMA\n"));		/* Fire up the DMA engine again if it stopped */		d->dma_enable = 1;		descr = in64(MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));		out64(d->ff.ringsz-descr, MAC2_DMARX0_CSR(R_MAC_DMA_DSCR_CNT));	}#endif#endif	return count;}static int saa7114h_ioctl(struct video_device *vd, unsigned int cmd, void *arg){	struct saa7114h *d = vd->priv;	int val, reg, retval = 0;	if (!d)		return -ENODEV;	switch (cmd) {	case VIDIOCGCHAN:	{		struct video_channel v;		if (copy_from_user(&v, arg, sizeof(v))) {			retval = -EFAULT;			break;		}		if (v.channel != 0) {			retval = -EINVAL;			break;		}		v.channel = 0;		strcpy(v.name, "Camera");		v.tuners = 0;		v.flags = 0;		v.type = VIDEO_TYPE_CAMERA;		v.norm = 0;		if (copy_to_user(arg, &v, sizeof(v)))			retval = -EFAULT;		break;	}		case VIDIOCSCHAN:	{		int v;		if (copy_from_user(&v, arg, sizeof(v)))			retval = -EFAULT;		if (retval == 0 && v != 0)			retval = -EINVAL;		break;	}	case VIDIOCGCAP:	{		struct video_capability b;		strcpy(b.name, "Philips SAA7114H Decoder");		b.type = VID_TYPE_CAPTURE /* | VID_TYPE_TELETEXT */ | VID_TYPE_SCALES;		b.channels = 1;		b.audios = 0;		b.maxwidth = MAX_HORIZ;		b.maxheight = MAX_VERT;		/* XXXKW find real values */		b.minwidth = 48;		b.minheight = 48;		if (copy_to_user(arg, &b, sizeof(b)))			retval = -EFAULT;		break;	}	/* image properties */	case VIDIOCGPICT:		if (copy_to_user(arg, &d->vp, sizeof(struct video_picture)))			retval = -EFAULT;		break;			case VIDIOCSPICT:	{		struct video_picture vp;		/* copy_from_user */		if (copy_from_user(&vp, arg, sizeof(vp))) {			retval = -EFAULT;			break;		}		down(&d->param_lock);		/* brightness, colour, contrast need not check 0-65535 */		memcpy( &d->vp, &vp, sizeof(vp) );		/* update cam->params.colourParams */		saa7114h_set_cparams(d);		up(&d->param_lock);		break;	}	/* get/set capture window */	case VIDIOCGWIN:		if (copy_to_user(arg, &d->vw, sizeof(struct video_window)))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?