plan 9 kernel history: overview | file list | diff list

1999/0430/pc/devlml.c (diff list | history)

pc/devlml.c on 1999/0422
1999/0422    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
#include	"io.h" 
 
#include	"devlml.h" 
 
// Lml 22 driver 
 
enum{ 
	Q819, 
	Q856, 
1999/0428    
	Qreg, 
1999/0422    
	Qvideo, 
	Qjframe, 
}; 
 
static Dirtab viddir[]={ 
//	 name,		 qid,	  size,		mode 
	"vid819",	{Q819},		0,		0644, 
	"vid856",	{Q856},		0,		0644, 
1999/0428    
	"vidreg",	{Qreg},		0,		0644, 
1999/0422    
	"video",	{Qvideo},	0,		0666, 
	"jframe",	{Qjframe},	0,		0666, 
}; 
 
CodeData *	codeData; 
 
1999/0424    
int			currentBuffer; 
int			currentBufferLength; 
void *		currentBufferPtr; 
int			frameNo; 
Rendez		sleeper; 
int			singleFrame; 
int			bufferPrepared; 
int			hdrPos; 
int			nopens; 
1999/0429    
uchar		q856[3]; 
1999/0424    
 
static FrameHeader frameHeader = { 
	MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8, 
	{ 'L', 'M', 'L', '\0'}, 
	-1, 0, 0, 0, 0 
}; 
 
1999/0423    
static void 
1999/0429    
i2c_pause(void) { 
1999/0422    
 
1999/0423    
	microdelay(I2C_DELAY); 
} 
 
1999/0422    
static void 
1999/0429    
i2c_waitscl(void) { 
1999/0423    
	int i; 
	ulong a; 
 
	for(i=0;;i++) { 
		a = readl(pciBaseAddr + ZR36057_I2C_BUS); 
		if (a & ZR36057_I2C_SCL) break; 
		if (i>I2C_TIMEOUT) error(Eio); 
	} 
} 
 
static void 
1999/0429    
i2c_start(void) { 
1999/0423    
 
	writel(ZR36057_I2C_SCL|ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_waitscl(); 
	i2c_pause(); 
1999/0423    
 
	writel(ZR36057_I2C_SCL, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
 
	writel(0, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
} 
 
static void 
1999/0429    
i2c_stop(void) { 
1999/0423    
	// the clock should already be low, make sure data is 
	writel(0, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
 
	// set clock high and wait for device to catch up 
	writel(ZR36057_I2C_SCL, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_waitscl(); 
	i2c_pause(); 
1999/0423    
 
	// set the data high to indicate the stop bit 
	writel(ZR36057_I2C_SCL|ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
} 
 
1999/0429    
static void i2c_wrbit(int bit) { 
1999/0423    
	if (bit){ 
		writel(ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); // set data 
1999/0429    
		i2c_pause(); 
1999/0423    
		writel(ZR36057_I2C_SDA|ZR36057_I2C_SCL, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
		i2c_waitscl(); 
		i2c_pause(); 
1999/0423    
		writel(ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
		i2c_pause(); 
1999/0423    
	} else { 
		writel(0, pciBaseAddr + ZR36057_I2C_BUS); // clr data 
1999/0429    
		i2c_pause(); 
1999/0423    
		writel(ZR36057_I2C_SCL, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
		i2c_waitscl(); 
		i2c_pause(); 
1999/0423    
		writel(0, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
		i2c_pause(); 
1999/0423    
	} 
} 
 
static int 
1999/0429    
i2c_rdbit(void) { 
1999/0423    
	int bit; 
	// the clk line should be low 
 
	// ensure we are not asserting the data line 
	writel(ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
 
	// set the clock high and wait for device to catch up 
	writel(ZR36057_I2C_SDA|ZR36057_I2C_SCL, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_waitscl(); 
	i2c_pause(); 
1999/0423    
 
	// the data line should be a valid bit 
	bit = readl(pciBaseAddr+ZR36057_I2C_BUS); 
	if (bit & ZR36057_I2C_SDA){ 
		bit = 1; 
	} else { 
		bit = 0; 
	} 
 
	// set the clock low to indicate end of cycle 
	writel(ZR36057_I2C_SDA, pciBaseAddr + ZR36057_I2C_BUS); 
1999/0429    
	i2c_pause(); 
1999/0423    
 
	return bit; 
} 
 
static int 
1999/0429    
i2c_rdbyte(uchar *v) { 
1999/0423    
	int i, ack; 
	uchar res; 
 
	res = 0; 
	for (i=0;i<8;i++){ 
		res  = res << 1; 
1999/0429    
		res += i2c_rdbit(); 
1999/0423    
	} 
 
1999/0429    
	ack = i2c_rdbit(); 
1999/0423    
 
	*v = res; 
 
	return ack; 
} 
 
static int 
1999/0429    
i2c_wrbyte(uchar v) { 
1999/0423    
	int i, ack; 
 
	for (i=0;i<8;i++){ 
1999/0429    
		i2c_wrbit(v & 0x80); 
1999/0423    
		v = v << 1; 
	} 
 
1999/0429    
	ack = i2c_rdbit(); 
1999/0423    
 
	return ack; 
} 
 
static void 
1999/0429    
i2c_write_bytes(uchar addr, uchar sub, uchar *bytes, long num) { 
1999/0423    
	int ack; 
	long i; 
 
1999/0429    
	i2c_start(); 
1999/0423    
 
1999/0429    
	ack = i2c_wrbyte(addr); 
1999/0423    
	if (ack == 1) error(Eio); 
 
1999/0429    
	ack = i2c_wrbyte(sub); 
1999/0423    
	if (ack == 1) error(Eio); 
 
	for(i=0;i<num;i+=1){ 
1999/0429    
		ack = i2c_wrbyte(bytes[i]); 
1999/0423    
		if (ack == 1) error(Eio); 
	} 
 
1999/0429    
	i2c_stop(); 
1999/0423    
} 
 
1999/0424    
static int 
1999/0429    
i2c_bt856rd8(void) { 
	uchar ret; 
 
	i2c_start (); 
 
	if (i2c_wrbyte(BT856Addr + 1) == 1 
	 || i2c_rdbyte(&ret) == 0) { 
		i2c_stop (); 
		return -1; 
	} 
 
	i2c_stop (); 
	return ret; 
} 
 
static int 
i2c_rd8(int addr, int sub) 
1999/0423    
{ 
	uchar msb; 
 
1999/0429    
	i2c_start(); 
1999/0423    
 
1999/0429    
	if (i2c_wrbyte(addr) == 1 
	 || i2c_wrbyte(sub) == 1) { 
		i2c_stop(); 
1999/0424    
		return -1; 
1999/0423    
	} 
 
1999/0429    
	i2c_start(); 
1999/0423    
 
1999/0429    
	if (i2c_wrbyte(addr+1) == 1 
	 || i2c_rdbyte(&msb) == 0){ 
		i2c_stop(); 
1999/0424    
		return -1; 
1999/0423    
	} 
 
1999/0429    
	i2c_stop(); 
1999/0423    
 
	return msb; 
} 
 
1999/0424    
static int 
1999/0429    
i2c_wr8(uchar addr, uchar sub, uchar msb) { 
1999/0424    
	 
1999/0429    
	i2c_start(); 
1999/0424    
 
1999/0429    
	if (i2c_wrbyte(addr) == 1 
	 || i2c_wrbyte(sub) == 1 
	 || i2c_wrbyte(msb) == 1) 
1999/0424    
		return 0; 
	 
1999/0429    
	i2c_stop(); 
1999/0424    
	 
	return 1; 
} 
 
1999/0423    
static int 
1999/0424    
prepareBuffer(CodeData * this, int bufferNo) { 
  if(bufferNo >= 0 && bufferNo < NBUF && (this->statCom[bufferNo] & STAT_BIT)) { 
    this->statCom[bufferNo] = this->statComInitial[bufferNo]; 
    return this->fragmDescr[bufferNo].fragmLength; 
  } else 
    return -1; 
} 
1999/0423    
 
1999/0424    
static int 
getProcessedBuffer(CodeData* this){ 
	static lastBuffer=NBUF-1; 
	int lastBuffer0 = lastBuffer; 
 
	while (1) {  
		lastBuffer = (lastBuffer+1) % NBUF; 
		if(this->statCom[lastBuffer]&STAT_BIT) 
			return lastBuffer; 
		if(lastBuffer==lastBuffer0) 
			break; 
1999/0423    
	} 
1999/0424    
	return -1; 
1999/0423    
} 
 
1999/0424    
static int 
getBuffer(CodeData *this, int bufferNo, void** bufferPtr, int* frameNo) { 
	int codeLength; 
	if(this->statCom[bufferNo] & STAT_BIT) { 
		*bufferPtr = (void*)this->fragmDescr[bufferNo].fragmAddress; 
		*frameNo = this->statCom[bufferNo] >> 24; 
		codeLength=((this->statCom[bufferNo] & 0x00FFFFFF) >> 1); 
		return codeLength; 
	} else 
		return -1; 
} 
1999/0423    
 
1999/0424    
static long 
vread(Chan *, void *va, long count, vlong pos) { 
	int prevFrame; 
	//  how much bytes left to transfer for the header 
	int hdrLeft; 
	// Count of bytes that we need to copy into buf from code-buffer 
	// (different from count only while in header reading mode) 
	int cpcount = count; 
	// Count of bytes that we copied into buf altogether and will return 
	int retcount=0; 
	vlong thetime; 
	uchar *buf = va; 
 
	//print("devlml::vread() count=%ld pos=%lld\n", count, pos); 
 
	// If we just begin reading a file, pos would never be 0 otherwise 
	if (pos == 0 && hdrPos == -1) { 
		 currentBuffer = -1; 
		 currentBufferLength = 0; 
		 frameNo = -1; 
1999/0423    
	} 
1999/0424    
	prevFrame = frameNo; 
 
	// We get to the end of the current buffer, also covers just 
	// open file, since 0 >= -1 
	if(hdrPos == -1 && pos >= currentBufferLength) { 
		prepareBuffer(codeData, currentBuffer); 
		// if not the first buffer read and single frame mode - return EOF 
		if (currentBuffer != -1 && singleFrame) 
			return 0; 
		while((currentBuffer = getProcessedBuffer(codeData)) == -1) 
			sleep(&sleeper, return0, 0); 
		currentBufferLength = getBuffer(codeData, currentBuffer, 
			¤tBufferPtr, &frameNo); 
 
		pos = 0; // ?????????????? 
 
		// print("getBufffer %d -> %d 0x%x %d\n",currentBuffer, currentBufferLength, currentBufferPtr, frameNo); 
		if(frameNo != (prevFrame + 1) % 256) 
			print("Frames out of sequence: %d %d\n", prevFrame, frameNo); 
		// Fill in APP marker fields here 
		thetime = todget(); 
		frameHeader.sec = (ulong)(thetime / 1000000000LL); 
		frameHeader.usec = (ulong)(thetime % 1000000000LL) / 1000; 
		frameHeader.frameSize = currentBufferLength - 2 + sizeof(FrameHeader); 
		frameHeader.frameSeqNo++; 
		frameHeader.frameNo = frameNo; 
		hdrPos=0; 
	} 
 
	if (hdrPos != -1) { 
		hdrLeft = sizeof(FrameHeader) - hdrPos; 
		// Write the frame size here 
		if (count >= hdrLeft) { 
			memmove(buf, (char*)&frameHeader + hdrPos, hdrLeft); 
			retcount += hdrLeft; 
			cpcount = count - hdrLeft; 
			pos = sizeof(frameHeader.mrkSOI); 
			hdrPos = -1; 
		} else { 
			memmove(buf, (char*)&frameHeader + hdrPos, count); 
			hdrPos += count; 
			return count; 
		} 
	} 
 
	if(cpcount + pos > currentBufferLength) 
		cpcount = currentBufferLength - pos; 
 
	memmove(buf + retcount, (char *)currentBufferPtr + pos, cpcount); 
	retcount += cpcount; 
 
	//pr_debug("return %d %d\n",cpcount,retcount); 
	return retcount; 
1999/0423    
} 
 
1999/0424    
static long 
vwrite(Chan *, void *va, long count, vlong pos) { 
	//  how much bytes left to transfer for the header 
	int hdrLeft; 
	char *buf = va; 
 
	//print("devlml::vwrite() count=0x%x pos=0x%x\n", count, pos); 
 
	// We just started writing, not into the header copy 
	if(pos==0 && hdrPos == -1) { 
		 currentBuffer=-1; 
		 currentBufferLength=0; 
		 frameNo=-1; 
		 bufferPrepared = 0; 
	} 
 
	// We need next buffer to fill (either because we're done with the 
	// current buffer) of because we're just beginning (but not into the header) 
	if (hdrPos == -1 && pos >= currentBufferLength) { 
		while((currentBuffer = getProcessedBuffer(codeData)) == -1) 
			sleep(&sleeper, return0, 0); 
		// print("current buffer %d\n",currentBuffer); 
 
		getBuffer(codeData, currentBuffer, ¤tBufferPtr, &frameNo); 
		// We need to receive the header now 
		hdrPos = 0; 
	} 
	 
	// We're into the header processing  
	if (hdrPos != -1) { 
		// Calculate how many bytes we need to receive to fill the header 
		hdrLeft = sizeof(FrameHeader) - hdrPos; 
	 
		// If we complete or go over the header with this count 
		if (count >= hdrLeft) { 
			// Adjust count of bytes that remain to be copied into video buffer 
			count = count - hdrLeft;  
			memmove((char*)&frameHeader + hdrPos, buf, hdrLeft); 
			// Make sure we have a standard LML33 header 
			if (frameHeader.mrkSOI == MRK_SOI 
1999/0430    
			 && frameHeader.mrkAPP3 == MRK_APP3 
			 && strcmp(frameHeader.nm, APP_NAME) == 0) { 
1999/0424    
				//print("Starting new buffer len=0x%x frame=%d\n", frameHeader.frameSize, frameHeader.frameSeqNo); 
				// Obtain values we need for playback process from the header 
				currentBufferLength = frameHeader.frameSize; 
			} else if (singleFrame) { 
				currentBufferLength = FRAGSIZE; 
			} else { 
				// We MUST have header for motion video decompression 
				print("No frame size (APP3 marker) in MJPEG file\n"); 
				error(Eio); 
			} 
			// Finish header processing 
			hdrPos = -1; 
			// Copy the header into the playback buffer 
			memmove(currentBufferPtr, (char*)&frameHeader, sizeof(FrameHeader)); 
			// And set position just behind header for playback buffer write 
			pos = sizeof(FrameHeader); 
		} else { 
			memmove((char*)&frameHeader + hdrPos, buf, count); 
			hdrPos += count; 
			return count; 
		} 
	} else 
		hdrLeft = 0; 
 
	if(count + pos > currentBufferLength) { 
		count = currentBufferLength - pos; 
	} 
 
	memmove((char *)currentBufferPtr + pos, buf + hdrLeft, count); 
 
	pos += count; 
	// print("return 0x%x 0x%x\n",pos,count); 
 
	// Now is the right moment to initiate playback of the frame (if it's full) 
	if(pos >= currentBufferLength) { 
		// We have written the frame, time to display it 
		//print("Passing written buffer to 067\n"); 
		prepareBuffer(codeData, currentBuffer); 
		bufferPrepared = 1; 
	} 
	//print("return 0x%lx 0x%x 0x%x 0x%x\n",pos,count,hdrLeft+count,currentBufferLength); 
 
	return hdrLeft + count; 
} 
 
1999/0423    
static void lmlintr(Ureg *, void *); 
 
static void 
1999/0422    
vidreset(void) 
{ 
	ulong regpa; 
	int i; 
 
1999/0423    
	pcidev = pcimatch(nil, PCI_VENDOR_ZORAN, PCI_DEVICE_ZORAN_36067); 
	if (pcidev == nil) { 
		print("No zr36067 found.\n"); 
		return; 
	} 
1999/0422    
	codeData = (CodeData*)xspanalloc(sizeof(CodeData), BY2PG, 0); 
	if (codeData == nil) { 
		print("devlml: xspanalloc(%ux, %ux, 0)\n", sizeof(CodeData), BY2PG); 
		return; 
	} 
 
	print("Installing Motion JPEG driver %s\n", MJPG_VERSION);  
	print("Buffer size %ux\n", sizeof(CodeData));  
 
	// Get access to DMA memory buffer 
	memset(codeData, 0xAA, sizeof(CodeData)); 
	strncpy(codeData->idString, MJPG_VERSION, strlen(MJPG_VERSION)); 
 
	for(i = 0; i < NBUF; i++) { 
		codeData->statCom[i] = PADDR(&(codeData->fragmDescr[i])); 
		codeData->statComInitial[i] = codeData->statCom[i]; 
		codeData->fragmDescr[i].fragmAddress = 
1999/0423    
			(Fragment *)PADDR(&(codeData->frag[i])); 
1999/0422    
		// Length is in double words, in position 1..20 
		codeData->fragmDescr[i].fragmLength = (FRAGSIZE >> 1) | FRAGM_FINAL_B; 
	} 
 
	print("initializing LML33 board..."); 
 
1999/0423    
	pciPhysBaseAddr = (void *)(pcidev->mem[0].bar & ~0x0F); 
1999/0422    
 
1999/0423    
	print("zr36067 found at %lux\n", pciPhysBaseAddr); 
1999/0422    
 
1999/0423    
	regpa = upamalloc(pcidev->mem[0].bar & ~0x0F, pcidev->mem[0].size, 0); 
1999/0422    
	if (regpa == 0) { 
		print("lml: failed to map registers\n"); 
		return; 
	} 
1999/0423    
	pciBaseAddr = (ulong)KADDR(regpa); 
1999/0422    
 
	// make sure the device will respond to mem accesses 
	// (pcicmd_master | pcicmd_memory) -- probably superfluous 
1999/0423    
//	pcicfgw32(pcidev, PciPCR, 0x04 | 0x02); 
1999/0422    
 
	// set bus latency -- probably superfluous 
1999/0423    
//	pcicfgw8(pcidev, PciLTR, 64); 
1999/0422    
 
	// Interrupt handler 
1999/0423    
	intrenable(pcidev->intl, lmlintr, nil, pcidev->tbdf); 
1999/0422    
 
	print("LML33 Installed\n");  
	return;  
} 
 
static Chan* 
vidattach(char *spec) 
{ 
	return devattach('V', spec); 
} 
 
static int 
vidwalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, viddir, nelem(viddir), devgen); 
} 
 
static void 
vidstat(Chan *c, char *dp) 
{ 
	devstat(c, dp, viddir, nelem(viddir), devgen); 
} 
 
static Chan* 
vidopen(Chan *c, int omode) 
{ 
	c->aux = 0; 
	switch(c->qid.path){ 
	case Q819: 
	case Q856: 
1999/0428    
	case Qreg: 
1999/0422    
		break; 
	case Qvideo: 
	case Qjframe: 
1999/0424    
		if (nopens) 
			error(Einuse); 
		nopens = 1; 
		singleFrame = (c->qid.path == Qjframe) ? 1 : 0;; 
		currentBuffer = 0; 
		currentBufferLength = 0; 
		currentBufferPtr = 0; 
		frameNo = 0; 
		bufferPrepared = 0; 
		hdrPos = -1; 
1999/0422    
		// allow one open total for these two 
		break; 
	} 
	return devopen(c, omode, viddir, nelem(viddir), devgen); 
} 
 
static void 
vidclose(Chan *c) 
{ 
	switch(c->qid.path){ 
	case Q819: 
	case Q856: 
1999/0428    
	case Qreg: 
1999/0422    
	case Qvideo: 
	case Qjframe: 
		authclose(c); 
	} 
} 
 
static long 
1999/0424    
vidread(Chan *c, void *va, long n, vlong off) { 
	int i, d; 
	uchar *buf = va; 
1999/0423    
 
1999/0422    
	switch(c->qid.path){ 
	case Q819: 
1999/0424    
		if (off < 0 || off + n > 0x20) 
1999/0423    
			return 0; 
1999/0424    
		for (i = 0; i < n; i++) { 
1999/0429    
			if ((d = i2c_rd8(BT819Addr, off++)) < 0) break; 
1999/0424    
			*buf++ = d; 
		} 
		return n - i; 
1999/0422    
	case Q856: 
1999/0429    
		if (n != 1) 
1999/0423    
			return 0; 
1999/0429    
		switch ((int)off) { 
		case 0: 
			if ((d = i2c_bt856rd8()) < 0) 
				return 0; 
			*buf = d; 
			break; 
		case 0xDA: 
			*buf = q856[0]; 
			break; 
		case 0xDC: 
			*buf = q856[1]; 
			break; 
		case 0xDE: 
			*buf = q856[2]; 
			break; 
		default: 
			return 0; 
1999/0424    
		} 
1999/0429    
		return 1; 
1999/0428    
	case Qreg: 
1999/0430    
		if (off < 0 || off + n > 0x400) 
1999/0424    
			return 0; 
1999/0428    
		switch(n) { 
		case 1: 
			*buf = readb(pciBaseAddr + off); 
			break; 
		case 2: 
1999/0430    
			if (off & (n-1)) return 0; 
1999/0428    
			*(short *)buf = readw(pciBaseAddr + off); 
			break; 
		case 4: 
1999/0430    
			if (off & (n-1)) return 0; 
1999/0424    
			*(long *)buf = readl(pciBaseAddr + off); 
1999/0428    
			break; 
		default: 
			return 0; 
1999/0424    
		} 
1999/0428    
		return n; 
1999/0422    
	case Qvideo: 
	case Qjframe: 
1999/0424    
		return vread(c, buf, n, off); 
1999/0422    
	} 
} 
 
static long 
1999/0424    
vidwrite(Chan *c, void *va, long n, vlong off) { 
	int i; 
	uchar *buf = va; 
1999/0423    
 
	switch(c->qid.path){ 
	case Q819: 
1999/0424    
		if (off < 0 || off + n > 0x20) 
1999/0423    
			return 0; 
1999/0424    
		for (i = n; i > 0; i--) 
1999/0429    
			if (i2c_wr8(BT819Addr, off++, *buf++) == 0) 
1999/0424    
				break; 
		return n - i; 
1999/0423    
	case Q856: 
1999/0429    
		if (n != 1 || off < 0xda || off + n > 0xe0) 
1999/0423    
			return 0; 
1999/0429    
		if (i2c_wr8(BT856Addr, off, *buf) == 0) 
				return 0; 
		switch ((int)off) { 
		case 0xDA: 
			q856[0] = *buf; 
			break; 
		case 0xDC: 
			q856[1] = *buf; 
			break; 
		case 0xDE: 
			q856[2] = *buf; 
			break; 
		} 
		return 1; 
1999/0428    
	case Qreg: 
1999/0424    
		if (off < 0 || off + n > 0x200 || (off & 0x3)) 
			return 0; 
1999/0428    
		switch (n) { 
		case 1: 
			writeb(*buf, pciBaseAddr + off); 
			break; 
		case 2: 
			writew(*(short *)buf, pciBaseAddr + off); 
			break; 
		case 4: 
1999/0424    
			writel(*(long *)buf, pciBaseAddr + off); 
1999/0428    
			break; 
		default: 
			return 0; 
1999/0424    
		} 
1999/0428    
		return n; 
1999/0423    
	case Qvideo: 
	case Qjframe: 
1999/0424    
		return vwrite(c, buf, n, off); 
1999/0423    
	} 
1999/0422    
} 
 
Dev viddevtab = { 
	'V', 
	"video", 
 
	vidreset, 
	devinit, 
	vidattach, 
	devclone, 
	vidwalk, 
	vidstat, 
	vidopen, 
	devcreate, 
	vidclose, 
	vidread, 
	devbread, 
	vidwrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 
 
static void 
1999/0424    
lmlintr(Ureg *, void *) { 
	ulong flags = readl(pciBaseAddr+ZR36057_INTR_STAT); 
	 
//  print("MjpgDrv_intrHandler stat=0x%08x\n", flags); 
1999/0422    
 
1999/0424    
	// Reset all interrupts from 067 
	writel(0xff000000, pciBaseAddr + ZR36057_INTR_STAT); 
1999/0423    
 
1999/0424    
	if(flags & ZR36057_INTR_JPEGREP) 
			wakeup(&sleeper); 
	return; 
1999/0422    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)