~kris/9p

9hist

dd7e4eebb79a4d3f7c27ef6fa3d61db46030ffc9 — David du Colombier 27 years ago 1cac83d
Plan 9 from Bell Labs 1999-04-24
6 files changed, 405 insertions(+), 104 deletions(-)

M alphapc/arch164.c
M alphapc/dma.c
M alphapc/io.h
M ip/il.c
M pc/devlml.c
M pc/devlml.h
M alphapc/arch164.c => alphapc/arch164.c +27 -6
@@ 27,6 27,26 @@ ident(void)
	return 0;	/* bug! */
}

static uvlong* sgmap;

static void
sginit(void)
{
	ulong pa;
	uvlong *pte;

	sgmap = xspanalloc(BY2PG, BY2PG, 0);
	memset(sgmap, 0, BY2PG);

	pte = sgmap;
	for(pa = 0; pa < 8*1024*1024; pa += BY2PG)
		*pte++ = ((pa>>PGSHIFT)<<1)|1;

	wind[0x400/4] = ISAWINDOW|2;
	wind[0x440/4] = 0x00700000;
	wind[0x480/4] = PADDR(sgmap);
}

static void *
kmapio(ulong space, ulong offset, int size)
{


@@ 54,17 74,18 @@ coreinit(void)
	}
	coresave[0] = core[0x140/4];

#ifdef notdef
	/* disable windows */
	wind[0x400/4] = 0;
	wind[0x500/4] = 0;
	wind[0x600/4] = 0;
	wind[0x700/4] = 0;

	/* direct map bottom 1G PCI target space to KZERO in window 1 */
	wind[0x500/4] = PCIWINDOW|1;
	wind[0x540/4] = 0x3ff00000;
	wind[0x580/4] = 0;

	/* disable other windows */
	wind[0x400/4] = 0;
	wind[0x600/4] = 0;
	wind[0x700/4] = 0;
#endif /* notdef */
sginit();

	/* clear error state */
	core[0x8200/4] = 0x7ff;

M alphapc/dma.c => alphapc/dma.c +13 -2
@@ 132,6 132,7 @@ dmasetup(int chan, void *va, long len, int isread)
	 *  if this isn't kernel memory or crossing 64k boundary or above 16 meg
	 *  use the bounce buffer.
	 */
print("va%lux+", va);
#ifdef notdef
	pa = PADDR(va);
	if((((ulong)va)&0xF0000000) != KZERO


@@ 151,7 152,7 @@ dmasetup(int chan, void *va, long len, int isread)
	else
		xp->len = 0;
#else
	pa = PCIWADDR(va);
	pa = ISAWADDR(va);
#endif /* notdef */

	/*


@@ 164,11 165,12 @@ dmasetup(int chan, void *va, long len, int isread)
	outb(dp->addr[chan], pa>>dp->shift);		/* set address */
	outb(dp->addr[chan], pa>>(8+dp->shift));
	outb(dp->page[chan], pa>>16);
outb(0x400|dp->page[chan], pa>>24);
//outb(0x400|dp->page[chan], pa>>24);
	outb(dp->count[chan], (len>>dp->shift)-1);		/* set count */
	outb(dp->count[chan], ((len>>dp->shift)-1)>>8);
	outb(dp->sbm, chan);		/* enable the channel */
	iunlock(dp);
print("pa%lux+", pa);

	return len;
}


@@ 207,6 209,15 @@ dmaend(int chan)
	outb(dp->sbm, 4|chan);
	iunlock(dp);

{ int i;
outb(dp->cbp, 0);
i = inb(dp->addr[chan]);
i |= inb(dp->addr[chan])<<8;
i |= inb(dp->page[chan])<<16;
i |= inb(0x400|dp->page[chan])<<24;
print("X%uX+", i);
}

	xp = &dp->x[chan];
	if(xp->len == 0 || !xp->isread)
		return;

M alphapc/io.h => alphapc/io.h +2 -0
@@ 205,3 205,5 @@ typedef struct SCSIdev {

#define PCIWINDOW	0x40000000
#define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
#define ISAWINDOW	0x00800000
#define ISAWADDR(va)	(PADDR(va)+ISAWINDOW)

M ip/il.c => ip/il.c +28 -6
@@ 1024,6 1024,26 @@ ilbackoff(Ilcb *ic)
	ic->rexmit++;
}

// complain if two numbers not within an hour of each other
#define Tfuture (1000*60*60)
int
later(ulong t1, ulong t2, char *x)
{
	int dt;

	dt = t1 - t2;
	if(dt > 0) {
		if(dt > Tfuture)
			print("%s: way future %d\n", x, dt);
		return 1;
	}
	if(dt < -Tfuture) {
		print("%s: way past %d\n", x, -dt);
		return 1;
	}
	return 0;
}

void
ilackproc(void *x)
{


@@ 1046,7 1066,7 @@ loop:
		case Illistening:
			break;
		case Ilclosing:
			if(ic->timeout <= msec) {
			if(later(msec, ic->timeout, "timeout")) {
				if(ic->rexmit > MaxRexmit){
					ilhangup(p, nil);
					break;


@@ 1058,7 1078,7 @@ loop:

		case Ilsyncee:
		case Ilsyncer:
			if(ic->timeout <= msec) {
			if(later(msec, ic->timeout, "timeout")) {
				if(ic->rexmit > MaxRexmit){
					ilhangup(p, etime);
					break;


@@ 1069,11 1089,12 @@ loop:
			break;

		case Ilestablished:
			if(ic->recvd != ic->acksent && ic->acktime <= msec)
			if(ic->recvd != ic->acksent)
			if(later(msec, ic->acktime, "acktime"))
				ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);

			if(ic->querytime <= msec){
				if(msec - ic->lastrecv > DeathTime){
			if(later(msec, ic->querytime, "querytime")){
				if(later(msec, ic->lastrecv+DeathTime, "deathtime")){
					netlog(il->f, Logil, "il: hangup: deathtime\n");
					ilhangup(p, etime);
					break;


@@ 1082,7 1103,8 @@ loop:
				ic->querytime = msec + QueryTime;
			}

			if(ic->unacked != nil && ic->timeout <= msec) {
			if(ic->unacked != nil)
			if(later(msec, ic->timeout, "timeout")) {
				if(ic->rexmit > MaxRexmit){
					netlog(il->f, Logil, "il: hangup: too many rexmits\n");
					ilhangup(p, etime);

M pc/devlml.c => pc/devlml.c +313 -72
@@ 30,7 30,22 @@ static Dirtab viddir[]={
};

CodeData *	codeData;
MjpgDrv *	mjpgDrv;

int			currentBuffer;
int			currentBufferLength;
void *		currentBufferPtr;
int			frameNo;
Rendez		sleeper;
int			singleFrame;
int			bufferPrepared;
int			hdrPos;
int			nopens;

static FrameHeader frameHeader = {
	MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8,
	{ 'L', 'M', 'L', '\0'},
	-1, 0, 0, 0, 0
};

static void
lml33_i2c_pause(void) {


@@ 182,38 197,25 @@ lml33_i2c_write_bytes(uchar addr, uchar sub, uchar *bytes, long num) {
	lml33_i2c_stop();
}

static uchar
static int
lml33_i2c_rd8(int addr, int sub)
{
	int ack;
	uchar msb;

	lml33_i2c_start();

	ack = lml33_i2c_wrbyte(addr);
	if (ack == 1){
		lml33_i2c_stop();
		error(Eio);
	}

	ack = lml33_i2c_wrbyte(sub);
	if (ack == 1){
	if (lml33_i2c_wrbyte(addr) == 1
	 || lml33_i2c_wrbyte(sub) == 1) {
		lml33_i2c_stop();
		error(Eio);
		return -1;
	}

	lml33_i2c_start();

	ack = lml33_i2c_wrbyte(addr+1);
	if (ack == 1){
		lml33_i2c_stop();
		error(Eio);
	}

	ack = lml33_i2c_rdbyte(&msb);
	if (ack == 0){
	if (lml33_i2c_wrbyte(addr+1) == 1
	 || lml33_i2c_rdbyte(&msb) == 0){
		lml33_i2c_stop();
		error(Eio);
		return -1;
	}

	lml33_i2c_stop();


@@ 221,6 223,21 @@ lml33_i2c_rd8(int addr, int sub)
	return msb;
}

static int
lml33_i2c_wr8(uchar addr, uchar sub, uchar msb) {
	
	lml33_i2c_start();

	if (lml33_i2c_wrbyte(addr) == 1
	 || lml33_i2c_wrbyte(sub) == 1
	 || lml33_i2c_wrbyte(msb) == 1)
		return 0;
	
	lml33_i2c_stop();
	
	return 1;
}

/*
 * The following mapping applies for the guests in the LML33
 *


@@ 252,7 269,7 @@ lml33_post_idle(void) {
}

// lml33_post_write writes a byte to a guest using postoffice mechanism
static void
static int
lml33_post_write(int guest, int reg, int v) {
	int w;



@@ 269,14 286,11 @@ lml33_post_write(int guest, int reg, int v) {
	writel(w, pciBaseAddr + ZR36057_POST_OFFICE);

	// wait for postoffice not busy
	w = lml33_post_idle();

	// decide if write went ok
	if (w == -1) error(Eio);
	return lml33_post_idle() == -1;
}

// lml33_post_read reads a byte from a guest using postoffice mechanism
static uchar
static int
lml33_post_read(int guest, int reg) {
	int w;



@@ 295,12 309,12 @@ lml33_post_read(int guest, int reg) {
	w = lml33_post_idle();

	// decide if read went ok
	if (w == -1) error(Eio);
	if (w == -1) return -1;

	return (uchar)(w & 0xFF);
	return w & 0xFF;
}

static void
static int
lml33_zr060_write(int reg, int v) {
	int guest_id;



@@ 308,10 322,10 @@ lml33_zr060_write(int reg, int v) {

	lml33_post_write(guest_id, 1, reg>>8 & 0x03);
	lml33_post_write(guest_id, 2, reg    & 0xff);
	lml33_post_write(guest_id, 3, v);
	return lml33_post_write(guest_id, 3, v);
}

static uchar
static int
lml33_zr060_read(int reg) {
	int guest_id;



@@ 323,24 337,203 @@ lml33_zr060_read(int reg) {
	return lml33_post_read(guest_id, 3);
}

long
chipread(long addr, char *buf, long n, long off) {
	long i;
static int
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;
}

	for (i = 0; i < n; i++) {
		*buf++ = lml33_i2c_rd8(addr, off++);
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;
	}
	return i;
	return -1;
}

long
post060read(char *buf, long n, long off) {
	long i;
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;
}

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;
	}
	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,
			&currentBufferPtr, &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;
}

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);

	for (i = 0; i < n; i++) {
		*buf++ = lml33_zr060_read(off++);
		getBuffer(codeData, currentBuffer, &currentBufferPtr, &frameNo);
		// We need to receive the header now
		hdrPos = 0;
	}
	return i;
	
	// 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
			 && frameHeader.mrkAPP3==MRK_APP3
			 && strcmp(frameHeader.nm,APP_NAME) == 0) {
				//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;
}

static void lmlintr(Ureg *, void *);


@@ 378,12 571,6 @@ vidreset(void)
		codeData->fragmDescr[i].fragmLength = (FRAGSIZE >> 1) | FRAGM_FINAL_B;
	}

	// Get dynamic kernel memory allocaton for the driver
	if((mjpgDrv = xallocz(sizeof(MjpgDrv), 0)) == nil) {
		print("LML33: can't allocate dynamic memory for MjpgDrv\n");
		return;
	}

	print("initializing LML33 board...");

	pciPhysBaseAddr = (void *)(pcidev->mem[0].bar & ~0x0F);


@@ 438,10 625,19 @@ vidopen(Chan *c, int omode)
	case Q856:
	case Q060:
	case Q067:
		// allow one open per file
		break;
	case Qvideo:
	case Qjframe:
		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;
		// allow one open total for these two
		break;
	}


@@ 463,51 659,89 @@ vidclose(Chan *c)
}

static long
vidread(Chan *c, void *buf, long n, vlong off) {
vidread(Chan *c, void *va, long n, vlong off) {
	int i, d;
	uchar *buf = va;

	switch(c->qid.path){
	case Q819:
		if (off < 0 || off + n > 20)
		if (off < 0 || off + n > 0x20)
			return 0;
		return chipread(BT819Addr, buf, n, off);
		for (i = 0; i < n; i++) {
			if ((d = lml33_i2c_rd8(BT819Addr, off++)) < 0) break;
			*buf++ = d;
		}
		return n - i;
	case Q856:
		if (off < 0xda || off + n > 0xe0)
			return 0;
		return chipread(BT856Addr, buf, n, off);
		for (i = 0; i < n; i++) {
			if ((d = lml33_i2c_rd8(BT856Addr, off++)) < 0) break;
			*buf++ = d;
		}
		return n - i;
	case Q060:
		return post060read(buf, n, off);
		if (off < 0 || off + n > 0x60)
			return 0;
		for (i = 0; i < n; i++) {
			if ((d = lml33_zr060_read(off++)) < 0) break;
			*buf++ = d;
		}
		return n - i;
	case Q067:
		if (off < 0 || off + n > 20 || (off & 0x3) || n != 4) return 0;
		*(long *)buf = readl(pciBaseAddr + off);
		return 4;
		if (off < 0 || off + n > 0x200 || (off & 0x3))
			return 0;
		for (i = n; i >= 4; i -= 4) {
			*(long *)buf = readl(pciBaseAddr + off);
			buf += 4;
			off += 4;
		}
		return n-i;
	case Qvideo:
	case Qjframe:
		return videoread(c, buf, n, off);
		return vread(c, buf, n, off);
	}
}

static long
vidwrite(Chan *c, void *va, long n, vlong off)
{
vidwrite(Chan *c, void *va, long n, vlong off) {
	int i;
	uchar *buf = va;

	switch(c->qid.path){
	case Q819:
		if (off < 0 || off + n > 20)
		if (off < 0 || off + n > 0x20)
			return 0;
		return chipwrite(BT819Addr, buf, n, off);
		for (i = n; i > 0; i--)
			if (lml33_i2c_wr8(BT819Addr, off++, *buf++) == 0)
				break;
		return n - i;
	case Q856:
		if (off < 0xda || off + n > 0xe0)
			return 0;
		return chipwrite(BT856Addr, buf, n, off);
		for (i = n; i > 0; i--)
			if (lml33_i2c_wr8(BT856Addr, off++, *buf++) == 0)
				break;
		return n - i;
	case Q060:
		return post060write(buf, n, off);
		if (off < 0 || off + n > 0x60)
			return 0;
		for (i = 0; i < n; i++)
			if (lml33_zr060_write(off++, *buf++) < 0)
				break;
		return n - i;
	case Q067:
		if (off < 0 || off + n > 20 || (off & 0x3) || n != 4) return 0;
		writel(*(long *)buf, pciBaseAddr + off);
		return 4;
		if (off < 0 || off + n > 0x200 || (off & 0x3))
			return 0;
		for (i = n; i >= 4; i -= 4) {
			writel(*(long *)buf, pciBaseAddr + off);
			buf += 4;
			off += 4;
		}
		return n-i;
	case Qvideo:
	case Qjframe:
		return videowrite(c, buf, n, off);
		return vwrite(c, buf, n, off);
	}
}



@@ 533,8 767,15 @@ Dev viddevtab = {
};

static void
lmlintr(Ureg *ur, void *)
{
lmlintr(Ureg *, void *) {
	ulong flags = readl(pciBaseAddr+ZR36057_INTR_STAT);
	
//  print("MjpgDrv_intrHandler stat=0x%08x\n", flags);

	// Reset all interrupts from 067
	writel(0xff000000, pciBaseAddr + ZR36057_INTR_STAT);

	if(flags & ZR36057_INTR_JPEGREP)
			wakeup(&sleeper);
	return;
}

M pc/devlml.h => pc/devlml.h +22 -18
@@ 87,6 87,8 @@ typedef struct {
#define ZR36057_POST_PEND				0x02000000
#define ZR36057_POST_TIME				0x01000000
#define ZR36057_POST_DIR				0x00800000
#define ZR36057_INTR_JPEGREP			0x08000000
#define ZR36057_INTR_STAT				0x03c

#define MB 0x100000
#define NBUF 4


@@ 101,6 103,7 @@ typedef struct {
#define readw(a)		(*(ushort *)(a))
#define readb(a)		(*(uchar *)(a))

typedef struct FrameHeader			FrameHeader;
typedef struct MjpgDrv				MjpgDrv;
typedef struct Fragment				Fragment;
typedef struct FragmentTable		FragmentTable;


@@ 113,12 116,12 @@ struct Fragment {
	uchar	fragbytes[FRAGSIZE];
};

struct FragmentTable {
struct FragmentTable {	// Don't modify this struct, used by h/w
	Fragment *		fragmAddress;			// Physical address
	ulong			fragmLength;
};

struct CodeData {
struct CodeData {	// Don't modify this struct, used by h/w
	char			idString[16];
	ulong			statCom[4];				// Physical address
	ulong			statComInitial[4];		// Physical address


@@ 126,23 129,24 @@ struct CodeData {
	Fragment		frag[4];
};

extern char static_MjpgDrv_GPL_Notice[];
extern struct file_operations static_MjpgDrv_fOps;

struct MjpgDrv {
	int					openCount;
	int					sleepFlag;
	struct wait_queue *	intrWaitQ;
};

static void *		pciPhysBaseAddr;
static ulong		pciBaseAddr;
static Pcidev *		pcidev;

void	LML33Board_mjpegGo(LML33Board*);

void	MjpgDrv_ctor(MjpgDrv*);
void	MjpgDrv_dtor(MjpgDrv*);
int		MjpgDrv_open(struct inode *iNode, struct file *filePtr);
void	MjpgDrv_release(struct inode *iNode, struct file *filePtr);
void	MjpgDrv_intrHandler(int irqNo, void *devId, struct pt_regs *ptRegs);
//If we're on the little endian architecture, then 0xFF, 0xD8 byte sequence is
#define MRK_SOI		0xD8FF
#define MRK_APP3	0xE3FF
#define APP_NAME	"LML"

struct FrameHeader	// Don't modify this struct, used by h/w
{
	short mrkSOI;
	short mrkAPP3;
	short lenAPP3;
	char nm[4];
	short frameNo;
	ulong sec;
	ulong usec;
	ulong frameSize;
	ulong frameSeqNo;
};