void do_ipp( Connection *conn, int length ) { IPP *reply; int len=0, pos; conn->ipp = ipp_new(); conn->ipp->data_left = length; if( getshort_conn( conn, &conn->ipp->version ) ) { if( getshort_conn( conn, &conn->ipp->operation ) ) { if( getint_conn( conn, &conn->ipp->request_id ) ) { conn->ipp->data_left -= 8; process_ipp_tags( conn ); } } } reply = NULL; switch( conn->ipp->operation ) { case IPP_GET_PRINTER_ATTR: reply = ipp_printer_attrs( conn->ipp ); break; case IPP_GET_JOBS: reply = ipp_get_jobs( conn->ipp ); break; case IPP_PRINT_JOB: // Special function printf( "Got print request.\n" ); ipp_print_job( conn, length ); break; case IPP_GET_JOB_ATTR: reply = ipp_job_attrs( conn->ipp ); break; default: ipp_pretty_print( conn->ipp ); reply = ipp_new(); reply->response = IPP_ERR_NOT_FOUND; // No such uri reply->version = 256; //IPP 1.0 reply->request_id = conn->ipp->request_id; ipp_add_tag( reply, IPP_TAG_OPERATIONS, NULL, NULL, 0, 0 ); ipp_copy_tag( reply, conn->ipp, IPP_TAG_OPERATIONS, "attributes-charset" ); ipp_copy_tag( reply, conn->ipp, IPP_TAG_OPERATIONS, "attributes-natural-language" ); } if( reply ) { #ifdef IPP_DEBUG printf( "Connection descriptor is: %d\n", conn->fd ); #endif len = ipp_write( reply, NULL, len ); pos = sprintf( conn->buffer, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: %d\r\n\r\n", len ); ipp_write( reply, conn->buffer + pos, len ); conn->used = len + pos; conn->buf_ptr = 0; conn->state = CONN_OUTPUT; ipp_free( reply ); } }
static irqreturn_t rk29_ipp_irq(int irq, void *dev_id) { DBG("rk29_ipp_irq %d \n",irq); //printk("rk29_ipp_irq %d \n",irq); #ifdef IPP_TEST hw_end = ktime_get(); #endif ipp_write(ipp_read(IPP_INT)|0x3c, IPP_INT); if(((ipp_read(IPP_INT)>>6)&0x3) !=0)// idle { printk("IPP is not idle!\n"); ipp_soft_reset(); drvdata->ipp_result = -EAGAIN; } //interacting with hardware done wq_condition = 1; #ifdef IPP_TEST irq_start = ktime_get(); #endif if(drvdata->issync)//sync { //wake_up_interruptible_sync(&hw_wait_queue); wake_up(&hw_wait_queue); } else//async { //power off schedule_delayed_work(&drvdata->power_off_work, msecs_to_jiffies(50)); drvdata->ipp_irq_callback(drvdata->ipp_result); //In the case of async call ,we wake up the wait queue here drvdata->ipp_async_result = drvdata->ipp_result; idle_condition = 1; wake_up_interruptible_sync(&blit_wait_queue); } return IRQ_HANDLED; }
static void ipp_soft_reset(void) { uint32_t i; uint32_t reg; ipp_write(1, IPP_SRESET); for(i = 0; i < IPP_RESET_TIMEOUT; i++) { reg = ipp_read( IPP_SRESET) & 1; if(reg == 0) break; udelay(1); } if(i == IPP_RESET_TIMEOUT) ERR("soft reset timeout.\n"); }
int ipp_blit(const struct rk29_ipp_req *req) { uint32_t rotate; uint32_t pre_scale = 0; uint32_t post_scale = 0; uint32_t pre_scale_w, pre_scale_h;//pre_scale para uint32_t post_scale_w = 0x1000; uint32_t post_scale_h = 0x1000; uint32_t pre_scale_output_w=0, pre_scale_output_h=0;//pre_scale output with&height uint32_t post_scale_input_w, post_scale_input_h;//post_scale input width&height uint32_t dst0_YrgbMst=0,dst0_CbrMst=0; uint32_t ret = 0; uint32_t deinterlace_config = 0; uint32_t src0_w = req->src0.w; uint32_t src0_h = req->src0.h; //printk("ipp_blit\n"); if (drvdata == NULL) { /* [email protected] : check driver is normal or not */ printk("%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__); return -EPERM; } drvdata->ipp_result = -1; //When ipp_blit_async is called in kernel space req->complete should NOT be NULL, otherwise req->complete should be NULL if(req->complete) { drvdata->ipp_irq_callback = req->complete; } else { drvdata->ipp_irq_callback = ipp_blit_complete; } ret = ipp_check_param(req); if(ret == -EINVAL) { printk("IPP invalid input!\n"); goto erorr_input; } rotate = req->flag; switch (rotate) { case IPP_ROT_90: //for rotation 90 degree DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt); switch(req->src0.fmt) { case IPP_XRGB_8888: dst0_YrgbMst = req->dst0.YrgbMst + req->dst0.w*4; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_RGB_565: dst0_YrgbMst = req->dst0.YrgbMst + req->dst0.w*2; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_Y_CBCR_H1V1: dst0_YrgbMst = req->dst0.YrgbMst + req->dst0.w; dst0_CbrMst = req->dst0.CbrMst + req->dst0.w*2; break; case IPP_Y_CBCR_H2V1: dst0_YrgbMst = req->dst0.YrgbMst + req->dst0.w; dst0_CbrMst = req->dst0.CbrMst + req->dst0.w*2; break; case IPP_Y_CBCR_H2V2: dst0_YrgbMst = req->dst0.YrgbMst+ req->dst0.w; dst0_CbrMst = req->dst0.CbrMst + req->dst0.w; break; default: break; } break; case IPP_ROT_180: //for rotation 180 degree DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt); switch(req->src0.fmt) { case IPP_XRGB_8888: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4+req->dst0.w*4; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_RGB_565: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_Y_CBCR_H1V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2; break; case IPP_Y_CBCR_H2V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w; break; case IPP_Y_CBCR_H2V2: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w+req->dst0.w; break; default: break; } break; case IPP_ROT_270: DBG("rotate %d, src0.fmt %d \n",rotate,req->src0.fmt); switch(req->src0.fmt) { case IPP_XRGB_8888: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_RGB_565: dst0_YrgbMst = req->dst0.YrgbMst +(req->dst0.h-1)*req->dst_vir_w*2; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_Y_CBCR_H1V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2; break; case IPP_Y_CBCR_H2V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2; break; case IPP_Y_CBCR_H2V2: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w; break; default: break; } break; case IPP_ROT_X_FLIP: DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt); switch(req->src0.fmt) { case IPP_XRGB_8888: dst0_YrgbMst = req->dst0.YrgbMst+req->dst0.w*4; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_RGB_565: dst0_YrgbMst = req->dst0.YrgbMst+req->dst0.w*2; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_Y_CBCR_H1V1: dst0_YrgbMst = req->dst0.YrgbMst+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+req->dst0.w*2; break; case IPP_Y_CBCR_H2V1: dst0_YrgbMst = req->dst0.YrgbMst+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+req->dst0.w; break; case IPP_Y_CBCR_H2V2: dst0_YrgbMst = req->dst0.YrgbMst+req->dst0.w; dst0_CbrMst = req->dst0.CbrMst+req->dst0.w; break; default: break; } break; case IPP_ROT_Y_FLIP: DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt); switch(req->src0.fmt) { case IPP_XRGB_8888: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_RGB_565: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2; dst0_CbrMst = req->dst0.CbrMst; break; case IPP_Y_CBCR_H1V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2; break; case IPP_Y_CBCR_H2V1: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w; break; case IPP_Y_CBCR_H2V2: dst0_YrgbMst = req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w; dst0_CbrMst = req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w; break; default: break; } break; case IPP_ROT_0: //for 0 degree DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt); dst0_YrgbMst = req->dst0.YrgbMst; dst0_CbrMst = req->dst0.CbrMst; break; default: ERR("ipp is not surpport degree!!\n" ); break; } //we start to interact with hw now wq_condition = 0; ipp_power_on(); //check if IPP is idle if(((ipp_read(IPP_INT)>>6)&0x3) !=0)// idle { printk("IPP staus is not idle,can not set register\n"); goto error_status; } /* Configure source image */ DBG("src YrgbMst 0x%x , CbrMst0x%x, %dx%d, fmt = %d\n", req->src0.YrgbMst,req->src0.CbrMst, req->src0.w, req->src0.h, req->src0.fmt); ipp_write(req->src0.YrgbMst, IPP_SRC0_Y_MST); if(IS_YCRCB(req->src0.fmt)) { ipp_write(req->src0.CbrMst, IPP_SRC0_CBR_MST); } //ipp_write(req->src0.h<<16|req->src0.w, IPP_SRC_IMG_INFO); ipp_write((ipp_read(IPP_CONFIG)&(~0x7))|req->src0.fmt, IPP_CONFIG); /* Configure destination image */ DBG("dst YrgbMst 0x%x , CbrMst0x%x, %dx%d\n", dst0_YrgbMst,dst0_CbrMst, req->dst0.w, req->dst0.h); ipp_write(dst0_YrgbMst, IPP_DST0_Y_MST); if(IS_YCRCB(req->src0.fmt)) { ipp_write(dst0_CbrMst, IPP_DST0_CBR_MST); } ipp_write(req->dst0.h<<16|req->dst0.w, IPP_DST_IMG_INFO); /*Configure Pre_scale*/ if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate)) { pre_scale = ((req->dst0.w <= req->src0.h/2) ? 1 : 0)||((req->dst0.h <= req->src0.w/2) ? 1 : 0); } else //other degree { pre_scale = ((req->dst0.w <= req->src0.w/2) ? 1 : 0)||((req->dst0.h <= req->src0.h/2) ? 1 : 0); } if(pre_scale) { if(((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))) { if((req->src0.w>req->dst0.h)) { pre_scale_w = (uint32_t)( req->src0.w/req->dst0.h);//floor } else { pre_scale_w = 1; } if((req->src0.h>req->dst0.w)) { pre_scale_h = (uint32_t)( req->src0.h/req->dst0.w);//floor } else { pre_scale_h = 1; } DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w); } else//0 180 x ,y { if((req->src0.w>req->dst0.w)) { pre_scale_w = (uint32_t)( req->src0.w/req->dst0.w);//floor } else { pre_scale_w = 1; } if((req->src0.h>req->dst0.h)) { pre_scale_h = (uint32_t)( req->src0.h/req->dst0.h);//floor } else { pre_scale_h = 1; } DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w); } //pre_scale only support 1/2 to 1/8 time if(pre_scale_w > 8) { if(pre_scale_w < 16) { pre_scale_w = 8; } else { printk("invalid pre_scale operation! Down scaling ratio should not be more than 16!\n"); goto error_scale; } } if(pre_scale_h > 8) { if(pre_scale_h < 16) { pre_scale_h = 8; } else { printk("invalid pre_scale operation! Down scaling ratio should not be more than 16!\n"); goto error_scale; } } if((req->src0.w%pre_scale_w)!=0) //ceil { pre_scale_output_w = req->src0.w/pre_scale_w+1; } else { pre_scale_output_w = req->src0.w/pre_scale_w; } if((req->src0.h%pre_scale_h)!=0)//ceil { pre_scale_output_h = req->src0.h/pre_scale_h +1; } else { pre_scale_output_h = req->src0.h/pre_scale_h; } //when fmt is YUV,make sure pre_scale_output_w and pre_scale_output_h are even if(IS_YCRCB(req->src0.fmt)) { if((pre_scale_output_w & 0x1) != 0) { pre_scale_output_w -=1; src0_w = pre_scale_output_w * pre_scale_w; } if((pre_scale_output_h & 0x1) != 0) { pre_scale_output_h -=1; src0_h = pre_scale_output_h * pre_scale_h; } } ipp_write((ipp_read(IPP_CONFIG)&0xffffffef)|PRE_SCALE, IPP_CONFIG); //enable pre_scale ipp_write((pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA); ipp_write(((pre_scale_output_h)<<16)|(pre_scale_output_w), IPP_PRE_IMG_INFO); } else//no pre_scale { ipp_write(ipp_read(IPP_CONFIG)&(~PRE_SCALE), IPP_CONFIG); //disable pre_scale ipp_write(0,IPP_PRE_SCL_PARA); ipp_write((req->src0.h<<16)|req->src0.w, IPP_PRE_IMG_INFO); } ipp_write(src0_h<<16|src0_w, IPP_SRC_IMG_INFO); /*Configure Post_scale*/ if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate)) { if (( (req->src0.h%req->dst0.w)!=0)||( (req->src0.w%req->dst0.h)!= 0)//non-interger down-scaling ||((req->src0.h/req->dst0.w)>8)||((req->src0.h/req->dst0.w)>8) //down-scaling ratio > 8 ||(req->dst0.w > req->src0.h) ||(req->dst0.h > req->src0.w)) //up-scaling { post_scale = 1; } else { post_scale = 0; } } else //0 180 x-flip y-flip { if (( (req->src0.w%req->dst0.w)!=0)||( (req->src0.h%req->dst0.h)!= 0)//non-interger down-scaling ||((req->src0.w/req->dst0.w)>8)||((req->src0.h/req->dst0.h)>8) //down-scaling ratio > 8 ||(req->dst0.w > req->src0.w) ||(req->dst0.h > req->src0.h)) //up-scaling { post_scale = 1; } else { post_scale = 0; } } if(post_scale) { if(pre_scale) { post_scale_input_w = pre_scale_output_w; post_scale_input_h = pre_scale_output_h; } else { post_scale_input_w = req->src0.w; post_scale_input_h = req->src0.h; } if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate)) { DBG("post_scale_input_w %d ,post_scale_input_h %d !!!\n",post_scale_input_w,post_scale_input_h); switch(req->src0.fmt) { case IPP_XRGB_8888: case IPP_RGB_565: case IPP_Y_CBCR_H1V1: //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer if(((4096*(post_scale_input_w-1))%(req->dst0.h-1))==0) { post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.h-1))-1; } else { post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.h-1)); } break; case IPP_Y_CBCR_H2V1: case IPP_Y_CBCR_H2V2: //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer if(((4096*(post_scale_input_w/2-1))%(req->dst0.h/2-1))==0) { post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.h/2-1))-1; } else { post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.h/2-1)); } break; default: break; } post_scale_h = (uint32_t)(4096*(post_scale_input_h -1)/(req->dst0.w-1)); DBG("1111 post_scale_w %x,post_scale_h %x!!! \n",post_scale_w,post_scale_h); } else// 0 180 x-flip y-flip { switch(req->src0.fmt) { case IPP_XRGB_8888: case IPP_RGB_565: case IPP_Y_CBCR_H1V1: //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer if(((4096*(post_scale_input_w-1))%(req->dst0.w-1))==0) { post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.w-1))-1; } else { post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.w-1)); } break; case IPP_Y_CBCR_H2V1: case IPP_Y_CBCR_H2V2: ////In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer if(((4096*(post_scale_input_w/2-1))%(req->dst0.w/2-1))==0) { post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.w/2-1))-1; } else { post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.w/2-1)); } break; default: break; } post_scale_h = (uint32_t)(4096*(post_scale_input_h -1)/(req->dst0.h-1)); } /*only support 1/2 to 4 times scaling,but two cases can pass 1.176*144->480*800, YUV420 2.128*128->480*800, YUV420 */ if(!((req->src0.fmt == IPP_Y_CBCR_H2V2)&& (((req->src0.w == 176)&&(req->src0.h == 144))||((req->src0.w == 128)&&(req->src0.h == 128)))&& ((req->dst0.w == 480)&&(req->dst0.h == 800)))) { if(post_scale_w<0x3ff || post_scale_w>0x1fff || post_scale_h<0x400 || post_scale_h>0x2000 ) { printk("invalid post_scale para!\n"); goto error_scale; } } ipp_write((ipp_read(IPP_CONFIG)&0xfffffff7)|POST_SCALE, IPP_CONFIG); //enable post_scale ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA); } else //no post_scale { DBG("no post_scale !!!!!! \n"); ipp_write(ipp_read(IPP_CONFIG)&(~POST_SCALE), IPP_CONFIG); //disable post_scale ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA); } /* Configure rotation */ if(IPP_ROT_0 == req->flag) { ipp_write(ipp_read(IPP_CONFIG)&(~ROT_ENABLE), IPP_CONFIG); } else { ipp_write(ipp_read(IPP_CONFIG)|ROT_ENABLE, IPP_CONFIG); ipp_write((ipp_read(IPP_CONFIG)&0xffffff1f)|(rotate<<5), IPP_CONFIG); } /*Configure deinterlace*/ if(req->deinterlace_enable == 1) { //only support YUV format if(IS_YCRCB(req->src0.fmt)) { //If pre_scale is enable, Deinterlace is done by scale filter if(!pre_scale) { //check the deinterlace parameters if((req->deinterlace_para0 < 32) && (req->deinterlace_para1 < 32) && (req->deinterlace_para2 < 32) && ((req->deinterlace_para0 + req->deinterlace_para1 + req->deinterlace_para2) == 32)) { deinterlace_config = (req->deinterlace_enable<<24) | (req->deinterlace_para0<<19) | (req->deinterlace_para1<<14) | (req->deinterlace_para2<<9); DBG("para0 %d, para1 %d, para2 %d,deinterlace_config %x\n",req->deinterlace_para0,req->deinterlace_para1,req->deinterlace_para2,deinterlace_config); #ifdef CONFIG_DEINTERLACE ipp_write((ipp_read(IPP_CONFIG)&0xFE0001FF)|deinterlace_config, IPP_CONFIG); #else printk("does not support deinterlacing!\n"); ipp_write(ipp_read(IPP_CONFIG)&(~DEINTERLACE_ENABLE), IPP_CONFIG); //disable deinterlace #endif } else { ERR("invalid deinterlace parameters!\n"); } } } else { ERR("only support YUV format!\n"); } } else { ipp_write(ipp_read(IPP_CONFIG)&(~DEINTERLACE_ENABLE), IPP_CONFIG); //disable deinterlace } /*Configure other*/ ipp_write((req->dst_vir_w<<16)|req->src_vir_w, IPP_IMG_VIR); //store clip mode if(req->store_clip_mode == 1) { ipp_write(ipp_read(IPP_CONFIG)|STORE_CLIP_MODE, IPP_CONFIG); } else { ipp_write(ipp_read(IPP_CONFIG)&(~STORE_CLIP_MODE), IPP_CONFIG); } /* Start the operation */ ipp_write(8, IPP_INT); ipp_write(1, IPP_PROCESS_ST); dsb(); dmac_clean_range(drvdata->ipp_base,drvdata->ipp_base+0x54); #ifdef IPP_TEST hw_start = ktime_get(); #endif goto error_noerror; error_status: error_scale: ret = -EINVAL; ipp_soft_reset(); ipp_power_off(NULL); erorr_input: error_noerror: drvdata->ipp_result = ret; //printk("ipp_blit done\n"); return ret; }
int main( int argc, char **argv ) { int num_polled = 1; struct pollfd *polls; struct sockaddr_in incoming; int i, n, pos, len; int new_fd; socklen_t addr_len; Connection *conn; IPP *response; signal( SIGUSR1, quit_handler ); // Temp printer for now if( argc < 2 ) { fprintf(stderr, "Missing argument pointing to location of printer definition file.\n" ); exit(1); } if(!init_printers( argv[1] )) { fprintf( stderr, "Unable to load printer definition file %s\n", argv[1] ); exit(1); } new_fd = StartListening(); polls = malloc( sizeof( struct pollfd ) * MAX_CLIENTS); polls[0].fd = new_fd; polls[0].events = POLLIN; for(;;) { // printf("."); for( conn = list_conn( NULL ), num_polled = 1; conn != NULL; conn = list_conn( conn ) ) { if( conn->state == CONN_BEGIN || conn->state == CONN_PRINTING_READ ) { polls[num_polled].fd = conn->fd; polls[num_polled++].events = POLLIN; } else if( conn->state == CONN_OUTPUT ) { polls[num_polled].fd = conn->fd; polls[num_polled++].events = POLLOUT; } } for( i = 0; i < array_len( printers ); i++ ) { printer = array_get( printers, i ); if( printer->state == PRINTER_PRINTING_WRITE ) { polls[num_polled].fd = printer->fd; polls[num_polled++].events = POLLOUT; } } poll( polls, num_polled, -1 ); // printf("o" ); for( i = 0; i < num_polled; i++ ) { if( polls[i].revents & POLLIN ) { // Read if( i == 0 ) { // Special case.. addr_len = sizeof( struct sockaddr_in ); new_fd = accept( polls[i].fd, (struct sockaddr *)&(incoming), &addr_len ); add_conn( new_fd ); } else { if( ( conn = get_conn( polls[i].fd ) ) ) { process_conn( conn ); } } } else if ( polls[i].revents & POLLNVAL ) { if( ( conn = get_conn( polls[i].fd ) ) ) remove_conn( conn ); } else if ( polls[i].revents & POLLOUT ) { if( ( conn = get_conn( polls[i].fd ) ) ) { if( ( n = write( conn->fd, conn->buffer+conn->buf_ptr, conn->used-conn->buf_ptr ) ) ) { conn->buf_ptr += n; if( conn->buf_ptr == conn->used ) { close( conn->fd ); remove_conn( conn ); } } } else { int e; for( e = 0; e < array_len( printers ); e++ ) { printer = array_get( printers, e ); if( printer->fd == polls[i].fd ) { if( ( n = write( printer->fd, printer->buffer+printer->buf_ptr, printer->used-printer->buf_ptr ) ) == 0 ) { #if 0 // ERROR WRITING TO PRINTER // Simple error support -- close printer fd if( ( conn = get_conn( printer->jobs->job.fd ) ) ) { fprintf( stderr, "Print job error.\n" ); response = ipp_new(); response->response = 0x0504; response->version = 256; // IPP 1.0 response->request_id = conn->ipp->request_id; ipp_add_tag( response, IPP_TAG_OPERATIONS, NULL, NULL, 0, 0 ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-charset" ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-natural-language" ); len = ipp_write( response, NULL, len ); pos = sprintf( conn->buffer, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: %d\r\n\r\n", len ); ipp_write( response, conn->buffer+pos, len ); conn->used = len + pos; conn->buf_ptr = 0; conn->state = CONN_OUTPUT; ipp_free( response ); } fprintf( stderr, "Marking printer closed.\n" ); close(printer->fd ); printer->state = PRINTER_CLOSED; #endif /* 0 */ } else { printer->buf_ptr += n; if( printer->buf_ptr == printer->used ) { printer->state = PRINTER_PRINTING_WAIT; printer->buf_ptr = printer->used = 0; if( ( conn = get_conn( printer->jobs->job.fd ) ) == NULL ) { printf( "Bad printer state.\n" ); } if( conn->ipp->data_left ) conn->state = CONN_PRINTING_READ; else { int pos, len, val; struct _ipp_jobs *old_job; IPP *response; // Generate a done message response = ipp_new(); response->response = 0x0000; // Success response->request_id = conn->ipp->request_id; response->version = 256; ipp_add_tag( response, IPP_TAG_OPERATIONS, NULL, NULL, 0, 0 ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-charset" ); ipp_copy_tag( response, conn->ipp, IPP_TAG_OPERATIONS, "attributes-natural-language" ); /* 2004/11/8 : Added to make XP printer utility report success status*/ ipp_add_tag( response, IPP_TAG_TEXT_WO_LANG, "status-message", "successful-ok", strlen( "successful-ok" ), 0 ); ipp_add_tag( response, IPP_TAG_JOBS, NULL, NULL, 0, 0 ); val = printer->jobs->job.id; ipp_add_tag( response, IPP_TAG_INTEGERS, "job-id", &val, 4, 0 ); val = 9; ipp_add_tag( response, IPP_TAG_ENUM, "job-state", &val, 4, 0 ); /* 9 = COMPLETED */ // Done len = ipp_write( response, NULL, len ); pos = sprintf( conn->buffer, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: %d\r\n\r\n", len ); ipp_write( response, conn->buffer + pos, len ); conn->used = len + pos; conn->buf_ptr = 0; conn->state = CONN_OUTPUT; /* 2004/11/8: added to free response */ ipp_free( response ); // The JOB being is printed is ALWAYS the first one old_job = printer->jobs; printer->jobs = old_job->next; free( old_job ); // Free the job printf( "Going to next job...\n" ); if( printer->jobs ) { if( ( conn = get_conn( printer->jobs->job.fd ) ) ) { if( conn->buf_ptr < conn->used ) { memcpy( printer->buffer, conn->buffer + conn->buf_ptr, conn->used - conn->buf_ptr ); printer->used = conn->used - conn->buf_ptr; printer->buf_ptr = 0; printer->state = PRINTER_PRINTING_WRITE; conn->state = CONN_PRINTING_WAIT; conn->ipp->data_left -= conn->used - conn->buf_ptr; } else { if( conn->ipp->data_left ) { printer->state = PRINTER_PRINTING_WAIT; conn->state = CONN_PRINTING_READ; } } } else { printf( "Unable to get connection for FD - %d.\n", printer->jobs->job.fd ); } } else { /* printer->state = PRINTER_OPEN; */ /* 2004/11/5 : put back into closed state so that kernel can remove lp0 when printer unplugged */ close(printer->fd); printer->fd = 0; printer->state = PRINTER_CLOSED; } } } } } } } } } } }