/* cqc.c Connectix QuickCam hardware interface Copyright (C) 1996, 1997 Alex Belits This software contains ideas and modified parts from qcam, written by Scott Laird. Copyright (C) 1996 by Scott Laird Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SCOTT LAIRD OR ALEX BELITS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "os-specific.h" #include "cqc.h" static int qcalarmflag; /************************************************** ** Create camera descriptor **************************************************/ struct qcam *qccreate(void){ struct qcam *qc; qc=malloc(sizeof(struct qcam)); if(!qc) return NULL; memset(qc,0,sizeof(struct qcam)); qc->red=1; qc->green=1; qc->blue=1; qc->x=0; qc->y=0; qc->xsize=320; qc->ysize=240; qc->decim=1; qc->bpp=24; qc->btpp=3; qc->black=100; qc->white=100; qc->blackoffset=250; qc->brightness=150; qc->contrast=104; qc->saturation=100; qc->hue=128; qc->lockfile=-1; qc->ioporthandle=-1; qc->scan_priority=SCAN_PRIORITY; return qc; } /************************************************** ** Delete camera descriptor, unlock/close file **************************************************/ void qcdelete(struct qcam *qc){ if(qc){ if(qc->ioporthandle>=0){ closeioport(qc->p0,qc->ioporthandle); } if(qc->lockfile>=0){ flock(qc->lockfile,LOCK_UN); close(qc->lockfile); } if(qc->frame) free(qc->frame); free(qc); } } void qcalarmhandler(int a){ qcalarmflag=0; } /************************************************** ** Set alarm **************************************************/ void qcsetalarm(void){ qcalarmflag=1; signal(SIGALRM,qcalarmhandler); alarm(QCAM_ALARM_TIME); } /************************************************** ** Reset alarm **************************************************/ void qcresetalarm(void){ qcalarmflag=0; } /************************************************** ** Send byte **************************************************/ inline int qcsend(const struct qcam *qc,unsigned char arg){ register unsigned char q1,argbyte0,argbyte1,echobyte,echobyte1,tries; argbyte0=arg&0xf0; argbyte1=arg<<4; OUTB(arg,qc->p0); OUTB(6,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); echobyte=q1&0xf0; tries=0; while(tries<100&&echobyte!=argbyte0){ /* don't worry, it doesn't happen often */ usleep(1); echobyte=INB(qc->p1)&0xf0; tries++; } if(echobyte!=argbyte0) return 1; OUTB(6|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); echobyte1=q1&0xf0; tries=0; while(tries<100&&echobyte1!=argbyte1){ /* don't worry, it doesn't happen often */ usleep(1); echobyte1=INB(qc->p1)&0xf0; tries++; } return echobyte1!=argbyte1; } /************************************************** ** Receive byte **************************************************/ inline unsigned char qcrecv(const struct qcam *qc){ register unsigned char q1,retbyte; OUTB(6,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); retbyte=q1&0xf0; OUTB(6|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); retbyte|=q1>>4; return retbyte; } /************************************************** ** Send command **************************************************/ inline int qccmd(const struct qcam *qc,unsigned char cmd,unsigned char param){ if(qcsend(qc,cmd)) return 1; return qcsend(qc,param); } /************************************************** ** Send command that returns value **************************************************/ inline unsigned int qcget(const struct qcam *qc,unsigned char cmd){ if(qcsend(qc,cmd)) return 0xffff; return (unsigned int) qcrecv(qc); } /************************************************** ** Initialize camera hardware, create/lock file **************************************************/ int qcinit(struct qcam *qc,int portnum){ char lockfilebuf[40]; uid_t ruid,euid; int i,serrno; unsigned char qcstatus; if(!portnum||!qc) return -3; ruid=getuid(); euid=geteuid(); if(euid){ /*return -1;*/ } if(qc->ioporthandle<0) qc->ioporthandle=openioport(portnum); if(qc->ioporthandle<0) return -2; if(qc->lockfile>=0){ flock(qc->lockfile,LOCK_UN); close(qc->lockfile); } sprintf(lockfilebuf,"/tmp/LOCK.qcam.0x%x",portnum); qc->lockfile=open(lockfilebuf,O_RDWR|O_CREAT,0600); if(qc->lockfile<0){ return -2; } if(flock(qc->lockfile,LOCK_EX)){ serrno=errno; close(qc->lockfile); qc->lockfile=-1; errno=serrno; return -2; } qc->p0=portnum; qc->p1=portnum+1; qc->p2=portnum+2; i=10; do{ OUTB(0xf,qc->p2); usleep(1000); OUTB(0xb,qc->p2); usleep(1000); OUTB(6,qc->p2); if(!qc->bidir){ /* The following is designed by Joe Jared and posted to QuickCam Drivers Mailing List as: outb 0x00,ctrl outb val1,dat outb 0x20,ctrl outb val2,dat outb ctrl,0x00 <- this is wrong in dat if dat=val1 then uni else bi. */ OUTB(0,qc->p2); OUTB(0x75,qc->p0); OUTB(0x20,qc->p2); OUTB(0,qc->p0); OUTB(0,qc->p2); qc->bidir=1+(INB(qc->p0)!=75); OUTB(6,qc->p2); } qcsetalarm(); qc->camv=qcget(qc,QCAM_CMD_SENDVERSION); if(qc->camv==0xffff){ if(i<=0){ qcresetalarm(); return -4; }else i--; }else i=0; }while(i>0&&qcalarmflag); if(qc->camv==QCAM_VER_COLOR){ qc->connv=(unsigned int)qcrecv(qc); qc->color=1; qc->bpp=24; qc->btpp=3; }else{ qc->connv=0; qc->color=0; if(qc->bpp!=4) qc->bpp=6; qc->btpp=1; } if(qc->color){ if(qccmd(qc,QCAM_CMD_COLOR_SETSPEED,QCAM_DEFAULT_SPEED)){ qcresetalarm(); return -5; } i=100; do{ qcstatus=qcget(qc,QCAM_CMD_SENDSTATUS); i--; if(qcstatus&(0xff^2)) usleep(10000); }while(((qcstatus&(0xff^2))&&i>0)&&qcalarmflag); }else{ OUTB(0x0b,qc->p2); usleep(250); OUTB(0x0e,qc->p2); } if(!qcalarmflag) return -4; qcresetalarm(); return 0; } /************************************************** ** Set image parameters **************************************************/ int qcsetimage(struct qcam *qc,unsigned char brightness, unsigned char contrast,unsigned char saturation, unsigned char hue,unsigned char black,unsigned char white, unsigned char blackoffset){ int i=100; unsigned char qcstatus; if(qc->color){ qc->black=black; qc->saturation=saturation; qc->hue=hue; } qc->contrast=contrast; qc->brightness=brightness; qc->white=white; qc->blackoffset=blackoffset; qcsetalarm(); if(qc->color){ if(qccmd(qc,QCAM_CMD_SETSATURATION,saturation)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_COLOR_SETHUE,hue)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_COLOR_SETCONTRAST,contrast)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBLACK,black)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBRIGHTNESS,brightness)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETWHITE,white)){ qcresetalarm(); return -1; } do{ qcstatus=qcget(qc,QCAM_CMD_SENDSTATUS); i--; if(qcstatus&(0xff^2)) usleep(10000); }while(((qcstatus&(0xff^2))&&i>0)&&qcalarmflag); }else{ if(qccmd(qc,QCAM_CMD_BW_SETCONTRAST,contrast)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBRIGHTNESS,brightness)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETWHITE,blackoffset)){ qcresetalarm(); return -1; } } if(!qcalarmflag) return -1; qcresetalarm(); return 0; } /************************************************** ** Set color balance **************************************************/ void qcsetcolor(struct qcam *qc,double red,double green,double blue){ double redbal,greenbal,bluebal,a,b,c,s=1./255.; int i; qc->red=red; qc->green=green; qc->blue=blue; b=0; if(red>s) b=red; if((greens) b=green; if((blues) b=blue; if(b>s){ redbal=red/b; greenbal=green/b; bluebal=blue/b; }else{ redbal=red; greenbal=green; bluebal=blue; } qc->redarray[0]=0; qc->redarray[255]=255; qc->greenarray[0]=0; qc->greenarray[255]=255; qc->bluearray[0]=0; qc->bluearray[255]=255; for(a=s,i=1;i<255;a+=s,i++){ if(redbal>=s){ c=a*redbal*255; if(c>=255.) c=255.; qc->redarray[i]=(unsigned char)rint(c); }else qc->redarray[i]=0; if(greenbal>=s){ c=a*greenbal*255; if(c>=255.) c=255.; qc->greenarray[i]=(unsigned char)rint(c); }else qc->greenarray[i]=0; if(bluebal>=s){ c=a*bluebal*255; if(c>=255.) c=255.; qc->bluearray[i]=(unsigned char)rint(c); }else qc->bluearray[i]=0; } } /************************************************** ** Internal - calculate parameter **************************************************/ inline unsigned char qcbwnumh(const struct qcam *qc,int pixels){ int val1,val2; val1=pixels/qc->decim*qc->bpp; val2=((qc->bidir==2)||qc->bpp==6)?24:8; return (unsigned char)((val1+val2-1)/val2); } /************************************************** ** Internal - calculate physical x offset **************************************************/ inline int phys_startx(x,y,xsize,ysize,direction,color){ if(direction&2){ if(direction&1){ return y+(color?10:14); }else{ return 338-x-xsize; } }else{ if(direction&1){ return 338-y-ysize; }else{ return x+(color?10:14); } } } /************************************************** ** Internal - calculate physical y offset **************************************************/ inline int phys_starty(x,y,xsize,ysize,direction,color){ if(direction&2){ if(direction&1){ return (color?247:243)-x-xsize; }else{ return (color?247:243)-y-ysize; } }else{ if(direction&1){ return x+1; }else{ return y+1; } } } /************************************************** ** Set frame, adjust parameters if necessary **************************************************/ int qchwframe(struct qcam *qc,int x,int y,int xsize,int ysize,int direction, int bpp,int decim){ unsigned char *rowptr; int i,lsize,loffset,lend; if(direction<0||direction>3) return -1; if(decim!=1&&decim!=2&&decim!=4) return -1; if(bpp!=4&&bpp!=6&&bpp!=24) return -1; if(x<0||y<0) return -1; if(qc->color){ if(direction&1){ if(y+ysize>328||x+xsize>246||ysize<2||ysize328||y+ysize>246||xsize<2||xsize324||x+xsize>242||ysize<2||ysize324||y+ysize>242||xsize<2||xsizedirection=direction; if(!qc->color) qc->bpp=bpp; else qc->bpp=24; qc->decim=decim; qc->vparam=0; if(qc->color){ switch(decim){ case 1: break; case 2: qc->vparam|=2; break; case 4: qc->vparam|=4; break; default: return -1; } switch(qc->btpp){ case 3: qc->vparam|=8|16; break; case 4: qc->vparam|=16; break; default: return -1; } }else{ switch(decim){ case 1: break; case 2: qc->vparam|=4; break; case 4: qc->vparam|=8; break; default: return -1; } switch(qc->bpp){ case 4: break; case 6: qc->vparam|=2; break; default: return -1; } } if(qc->bidir==2) qc->vparam|=1; if(qc->color) qc->vparam++; qcsetalarm(); xsize=xsize/decim*decim; ysize=ysize/decim*decim; qc->x=x; qc->y=y; qc->xsize=xsize; qc->ysize=ysize; loffset=phys_startx(x,y,xsize,ysize,direction,qc->color); lend=loffset+((direction&1)?ysize:xsize); if(loffset&1){ loffset--; } lsize=lend-loffset; if(qc->color){ if(lsize&1){ lsize++; } } if(lsize%decim) lsize+=decim-(lsize%decim); if(qccmd(qc,QCAM_CMD_SETLEFT,loffset/2)){ qcresetalarm(); return -2; } if(qccmd(qc,QCAM_CMD_SETTOP,phys_starty(x,y,xsize,ysize,direction,qc->color))){ qcresetalarm(); return -2; } if(qc->color){ if(qccmd(qc,QCAM_CMD_SETNUMV,(direction&1)?xsize:ysize)){ qcresetalarm(); return -2; } if(qccmd(qc,QCAM_CMD_SETNUMH,lsize/2)){ qcresetalarm(); return -2; } }else{ if(qccmd(qc,QCAM_CMD_SETNUMV,((direction&1)?xsize:ysize)/decim)){ qcresetalarm(); return -2; } if(qccmd(qc,QCAM_CMD_SETNUMH,qcbwnumh(qc,lsize))){ qcresetalarm(); return -2; } } qc->framesize=qc->xsize/decim*(qc->ysize/decim)*qc->btpp; if(qc->frame) free(qc->frame); if(direction&1){ qc->frame=(char*)malloc(2*qc->framesize+qc->ysize/decim*sizeof(char*)); if(qc->frame){ qc->frame1=qc->frame+qc->framesize; qc->rows=(unsigned char**)(qc->frame1+qc->framesize); }else{ qc->frame1=NULL; qc->rows=NULL; } }else{ qc->frame=(char*)malloc(qc->framesize+qc->ysize/decim*sizeof(char*)); qc->frame1=qc->frame; if(qc->frame) qc->rows=(unsigned char**)(qc->frame+qc->framesize); else qc->rows=NULL; } if(!qc->frame){ qcresetalarm(); return -3; } rowptr=qc->frame; for(i=0;iysize/decim;i++){ qc->rows[i]=rowptr; rowptr+=qc->xsize/decim*qc->btpp; } if(!qcalarmflag) return -2; qcresetalarm(); return 0; } /************************************************** ** Set scan priority **************************************************/ void qcsetpriority(struct qcam *qc,int priority){ qc->scan_priority=priority; } /************************************************** ** Wait for ready after setting **************************************************/ void qcwaitforready(const struct qcam *qc){ int i=100; unsigned char qcstatus; if(!qc->color) return; qcsetalarm(); do{ qcstatus=qcget(qc,QCAM_CMD_SENDSTATUS); i--; if(qcstatus&(0xff^2)) usleep(10000); }while(((qcstatus&(0xff^2))&&i>0)&&qcalarmflag); qcresetalarm(); } /************************************************** ** Set hardware again after initial setting once ** done **************************************************/ int qcsethw(struct qcam *qc){ int lsize,loffset,lend; qcsetalarm(); if(qc->color){ qcsetcolor(qc,qc->red,qc->green,qc->blue); if(qccmd(qc,QCAM_CMD_SETSATURATION,qc->saturation)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_COLOR_SETHUE,qc->hue)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_COLOR_SETCONTRAST,qc->contrast)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBLACK,qc->black)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBRIGHTNESS,qc->brightness)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETWHITE,qc->white)){ qcresetalarm(); return -1; } }else{ if(qccmd(qc,QCAM_CMD_BW_SETCONTRAST,qc->contrast)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETBRIGHTNESS,qc->brightness)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETWHITE,qc->blackoffset)){ qcresetalarm(); return -1; } } if((qc->xsize%qc->decim)||(qc->ysize%qc->decim)){ qcresetalarm(); return -1; } loffset=phys_startx(qc->x,qc->y,qc->xsize,qc->ysize,qc->direction,qc->color); lend=loffset+((qc->direction&1)?qc->ysize:qc->xsize); if(loffset&1){ loffset--; } lsize=lend-loffset; if(qc->color){ if(lsize&1){ lsize++; } } if(lsize%qc->decim) lsize+=qc->decim-(lsize%qc->decim); if(qccmd(qc,QCAM_CMD_SETLEFT,loffset/2)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETTOP,phys_starty(qc->x,qc->y,qc->xsize,qc->ysize, qc->direction,qc->color))){ qcresetalarm(); return -1; } if(qc->color){ if(qccmd(qc,QCAM_CMD_SETNUMV,(qc->direction&1)?qc->xsize:qc->ysize)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETNUMH,lsize/2)){ qcresetalarm(); return -1; } }else{ if(qccmd(qc,QCAM_CMD_SETNUMV,((qc->direction&1)?qc->xsize:qc->ysize)/qc->decim)){ qcresetalarm(); return -1; } if(qccmd(qc,QCAM_CMD_SETNUMH,qcbwnumh(qc,lsize))){ qcresetalarm(); return -1; } } qcwaitforready(qc); if(!qcalarmflag) return -1; qcresetalarm(); return 0; } /************************************************** ** Read frame **************************************************/ int qcreadframe(struct qcam *qc){ unsigned char *currptr,*frameend,qr,q0,q1,buf3[3],*buf3end=buf3+3; int finished=0; int wstep1,wstep2,pixelsleft,indummybuffer,addpixel,lsize,loffset,lend; unsigned int i,j,k,xsize,ysize,pixperline; unsigned char *rptr,*wptr; int oldpriority; unsigned char *startrow,*endrow,dummybuffer[400]; loffset=phys_startx(qc->x,qc->y,qc->xsize,qc->ysize,qc->direction,qc->color); lend=loffset+((qc->direction&1)?qc->ysize:qc->xsize); if(loffset&1){ loffset--; addpixel=1; }else addpixel=0; lsize=lend-loffset; if(qc->color){ if(lsize&1){ lsize++; } } if(lsize%qc->decim) lsize+=qc->decim-(lsize%qc->decim); if(qc->direction&1){ /* sizes for portrait/landscape camera directions */ xsize=qc->xsize/qc->decim; ysize=qc->ysize/qc->decim; pixperline=ysize; }else{ pixperline=qc->xsize/qc->decim; } if(!qc->frame1) return -1; /* error if not set properly */ currptr=qc->frame1; frameend=qc->frame1+qc->framesize; oldpriority=getpriority(PRIO_PROCESS,0); /* priority handling, requires userid=0 */ setpriority(PRIO_PROCESS,0,qc->scan_priority); qcsetalarm(); if(qccmd(qc,QCAM_CMD_SENDVFRAME,qc->vparam)){ /* reading */ setpriority(PRIO_PROCESS,0,oldpriority); /* if failed, returning */ qcresetalarm(); return -1; } startrow=currptr; if(qc->color){ /* color camera */ lsize*=3; pixperline*=3; endrow=startrow+pixperline; pixelsleft=lsize/qc->decim-pixperline; if(addpixel){ indummybuffer=1; currptr=dummybuffer+pixelsleft-3; }else indummybuffer=0; if(qc->bidir==2){ /* bidirectional */ OUTB(0x26|8,qc->p2); usleep(5); OUTB(0x26,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); OUTB(0x26|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); do{ OUTB(0x26,qc->p2); while(!((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr=(q0>>1)|((q1&8)?0x80:0); currptr++; *currptr=(q1&0xf0)^0x80; OUTB((0x26|8),qc->p2); while(((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr|=((q1^0x80)>>4); currptr++; *currptr=(q0>>1)|((q1&8)?0x80:0); currptr++; if(currptr==buf3end){ if(buf3[0]==0x7e){ if(buf3[1]==0x7e&&buf3[2]==0x7e){ currptr=buf3; }else{ currptr=frameend; } }else{ if(buf3[0]==0x0e&&buf3[1]==0&&buf3[2]==0x0f){ finished=1; } currptr=frameend; } }else{ if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft-=3; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } if(currptr>=frameend&&!indummybuffer){ currptr=buf3; } } }while((currptr=buf3&&currptrp2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); OUTB(6,qc->p2); usleep(5); OUTB(6|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); if(qcsend(qc,0)){ setpriority(PRIO_PROCESS,0,oldpriority); qcresetalarm(); return -3; } if(!finished){ setpriority(PRIO_PROCESS,0,oldpriority); qcresetalarm(); return -4; } }else{ /* unidirectional */ do{ *currptr=qcrecv(qc)^0x88; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft-=3; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } }while((currptrbpp==6){ /* 6 bpp */ if(qc->bidir==2){ /* bidirectional */ pixelsleft=qcbwnumh(qc,lsize)*4-pixperline; if(addpixel){ indummybuffer=1; currptr=dummybuffer+399; }else indummybuffer=0; OUTB(0x26|8,qc->p2); usleep(5); OUTB(0x26,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); OUTB(0x26|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); do{ OUTB(0x26,qc->p2); while(!((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr=63-((q0>>1)&0x3f); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=63-((q0&0x80)>>7|((q1&0xf8)>>2)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } OUTB((0x26|8),qc->p2); while(((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr=63-((q0>>1)&0x3f); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=63-((q0&0x80)>>7|((q1&0xf8)>>2)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } }while((currptrp2); usleep(5); OUTB(6,qc->p2); usleep(10); OUTB(6|8,qc->p2); }else{ /* unidirectional */ pixelsleft=qcbwnumh(qc,lsize)*4-pixperline; if(addpixel){ indummybuffer=1; currptr=dummybuffer+399; }else indummybuffer=0; do{ OUTB(6,qc->p2); while(!((q0=INB(qc->p1))&8)&&qcalarmflag); OUTB(6|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); *currptr=63-(((q0&0xf0)>>2)|(q1>>6)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } OUTB(6,qc->p2); while(!((q0=INB(qc->p1))&8)&&qcalarmflag); *currptr=63-((q1&0x30)|(q0>>4)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } OUTB(6|8,qc->p2); while(((q0=INB(qc->p1))&8)&&qcalarmflag); OUTB(6,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); *currptr=63-(((q0&0xf0)>>2)|(q1>>6)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } OUTB(6|8,qc->p2); while(((q0=INB(qc->p1))&8)&&qcalarmflag); *currptr=63-((q1&0x30)|(q0>>4)); currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } }while((currptrp2); usleep(10); OUTB(6|8,qc->p2); } }else{ /* 4 bpp */ if(qc->bidir==2){ /* bidirectional */ pixelsleft=qcbwnumh(qc,lsize)*6-pixperline; if(addpixel){ indummybuffer=1; currptr=dummybuffer+399; }else indummybuffer=0; OUTB(0x26|8,qc->p2); usleep(5); OUTB(0x26,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); OUTB(0x26|8,qc->p2); while(((q1=INB(qc->p1))&8)&&qcalarmflag); do{ OUTB(0x26,qc->p2); while(!((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr=(16-((q0>>1)&0x0f))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=(16-(((q0>>5)&0x07)|(q1&0x08)))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=(16-(q1>>4))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } OUTB((0x26|8),qc->p2); while(((q0=INB(qc->p0))&1)&&qcalarmflag); q1=INB(qc->p1); *currptr=(16-((q0>>1)&0x0f))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=(16-(((q0>>5)&0x07)|(q1&0x08)))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } *currptr=(16-(q1>>4))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } }while((currptrp2); usleep(5); OUTB(6,qc->p2); usleep(10); OUTB(6|8,qc->p2); }else{ /* unidirectional */ pixelsleft=qcbwnumh(qc,lsize)*2-pixperline; if(addpixel){ indummybuffer=1; currptr=dummybuffer+399; }else indummybuffer=0; do{ OUTB(6,qc->p2); while(!((q1=INB(qc->p1))&8)&&qcalarmflag); OUTB(6|8,qc->p2); *currptr=(16-(q1>>4))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } while(((q1=INB(qc->p1))&8)&&qcalarmflag); *currptr=(16-(q1>>4))&0x0f; currptr++; if(indummybuffer){ if(currptr-dummybuffer>=pixelsleft){ currptr=startrow; indummybuffer=0; } }else{ if(currptr>=endrow){ startrow=endrow; endrow=startrow+pixperline; if(addpixel&&currptr>=frameend) pixelsleft--; if(pixelsleft){ currptr=dummybuffer; indummybuffer=1; } } } }while((currptrp2); usleep(10); OUTB(6|8,qc->p2); } } } setpriority(PRIO_PROCESS,0,oldpriority); if(qc->color&&qc->btpp>=3&&(qc->red!=1.||qc->green!=1.||qc->blue!=1.)){ if(qc->direction&1){ currptr=qc->frame1; frameend=qc->frame1+qc->framesize; }else{ currptr=qc->frame; frameend=qc->frame+qc->framesize; } while(currptrredarray[*currptr]; currptr++; *currptr=qc->greenarray[*currptr]; currptr++; *currptr=qc->bluearray[*currptr]; currptr+=qc->btpp-2; } } switch(qc->direction){ case 0: break; case 2: rptr=qc->frame; wptr=qc->frame+qc->framesize-qc->btpp; while(rptrbtpp;k++){ qr=*wptr; *(wptr++)=*rptr; *(rptr++)=qr; } wptr-=2*qc->btpp; } break; case 1: case 3: if(qc->direction==1){ wstep1=(-xsize-1)*qc->btpp; wstep2=((ysize-1)*xsize)*qc->btpp-wstep1; rptr=qc->frame1; wptr=qc->frame+(ysize-1)*xsize*qc->btpp; }else{ wstep1=(xsize-1)*qc->btpp; wstep2=(-(ysize-1)*xsize-2)*qc->btpp-wstep1; rptr=qc->frame1; wptr=qc->frame+(xsize-1)*qc->btpp; } for(i=0;ibtpp;k++) *(wptr++)=*(rptr++); wptr+=wstep1; } wptr+=wstep2; } break; } setpriority(PRIO_PROCESS,0,oldpriority); if(!qcalarmflag) return -1; qcresetalarm(); return 0; } /************************************************** ** Get image exposure **************************************************/ int qcgetimageexposure(struct qcam *qc){ int histogram[256]; unsigned i,j,ncolors,npixels; unsigned char *currptr,*endptr; memset(histogram,0,256*sizeof(int)); currptr=qc->frame; endptr=qc->frame+qc->framesize; npixels=(endptr-currptr)/2; if(!npixels) npixels++; while(currptrcolor) ncolors=256; else if(qc->bpp==6) ncolors=64; else ncolors=16; for(i=0,j=0;jp0); if(i) return i; qcsetcolor(qc,qc->red,qc->green,qc->blue); if(qcsetimage(qc,qc->brightness,qc->contrast,qc->saturation,qc->hue, qc->black,qc->white,qc->blackoffset)) return -6; i=qchwframe(qc,qc->x,qc->y,qc->xsize,qc->ysize,qc->direction, qc->bpp,qc->decim); if(i) return i-6; else return 0; } /************************************************** ** Read the config file (requires initialization ** after doing that) **************************************************/ int qcreadconfigfile(struct qcam *qc,char *filename, char *cameraname,int quiet){ FILE *cfile; char tmpbuffer[256],*p,*p1,*p2; int section=0,pnumber=0,linenum=0,value; cfile=fopen(filename?filename:DEFAULTCONFIGFILENAME,"r"); if(!cfile){ if(!quiet) perror(filename?filename:DEFAULTCONFIGFILENAME); return -1; } while(fgets(tmpbuffer,255,cfile)==tmpbuffer){ linenum++; p=strchr(tmpbuffer,'\n'); if(p) *p=0; p=strchr(tmpbuffer,'\r'); if(p) *p=0; p=strchr(tmpbuffer,'#'); if(p) *p=0; p=tmpbuffer; while(*p&&isspace(*p)) p++; p1=p; while(*p1&&!isspace(*p1)) p1++; if(*p1){ *p1=0; p1++; while(*p1&&isspace(*p1)) p1++; } p2=p1; while(*p2&&!isspace(*p2)) p2++; if(*p2){ *p2=0; p2++; while(*p2&&isspace(*p2)) p2++; } if(!*p) pnumber=0; else if(!*p1) pnumber=1; else if(!*p2) pnumber=2; else pnumber=3; if(pnumber==2){ if(!strcasecmp(p,"camera")){ if(cameraname){ if(!strcasecmp(cameraname,p1)){ section=1; }else{ section=2; } }else{ section=2; } }else{ if(section!=2){ if(!strcasecmp(p,"port")){ if(!strncasecmp(p1,"0x",2)){ if(!sscanf(p1+2,"%x",&value)){ value=0; } }else{ value=atoi(p1); } if(value){ qc->p0=value; qc->p1=value+1; qc->p2=value+2; }else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"brightness")){ value=atoi(p1); if(value>=0&&value<=255) qc->brightness=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"contrast")){ value=atoi(p1); if(value>=0&&value<=255) qc->contrast=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"white")){ value=atoi(p1); if(value>=0&&value<=255) qc->white=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"blackoffset")||!strcasecmp(p,"whitebal")){ value=atoi(p1); if(value>=0&&value<=255) qc->blackoffset=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"saturation")){ value=atoi(p1); if(value>=0&&value<=255) qc->saturation=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"hue")){ value=atoi(p1); if(value>=0&&value<=255) qc->hue=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"black")){ value=atoi(p1); if(value>=0&&value<=255) qc->black=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"yoffset")){ value=atoi(p1); if(value>=0&&value<=326) qc->y=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"xoffset")){ value=atoi(p1); if(value>=0&&value<=326) qc->x=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"height")){ value=atoi(p1); if(value>=2&&value<=328) qc->ysize=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"width")){ value=atoi(p1); if(value>=2&&value<=328) qc->xsize=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"bpp")){ value=atoi(p1); if(value==4||value==6||value==24) qc->bpp=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"transfer")){ value=atoi(p1); if(value==1||value==2||value==4) qc->decim=value; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"direction")){ if(!strcasecmp(p1,"up")) qc->direction=0; else if(!strcasecmp(p1,"down")) qc->direction=2; else if(!strcasecmp(p1,"left")) qc->direction=3; else if(!strcasecmp(p1,"right")) qc->direction=1; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"porttype")){ if(!strcasecmp(p1,"bidirectional")) qc->bidir=2; else if(!strcasecmp(p1,"unidirectional")) qc->bidir=1; else if(!strcasecmp(p1,"unknown")) qc->bidir=0; else if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); }else{ if(!strcasecmp(p,"red")){ if(!sscanf(p1,"%lf",&qc->red)){ if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); } }else{ if(!strcasecmp(p,"green")){ if(!sscanf(p1,"%lf",&qc->green)){ if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); } }else{ if(!strcasecmp(p,"blue")){ if(!sscanf(p1,"%lf",&qc->blue)){ if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); } }else{ if(!strcasecmp(p,"priority")){ if(!sscanf(p1,"%d",&qc->scan_priority)){ if(!quiet) fprintf(stderr,"wrong value at the line %d \"%s %s\"\n",linenum,p,p1); } }else{ if(!quiet) fprintf(stderr,"syntax error at the line %d \"%s %s\"\n",linenum,p,p1); } } } } } } } } } } } } } } } } } } } } } } }else{ if(!quiet&&pnumber!=0) fprintf(stderr,"syntax error at the line %d \"%s %s %s\" %d\n", linenum,p,p1,p2,pnumber); } } fclose(cfile); return 0; }