static int rkusb_write_sdram( struct rkusb_dev *dev ) { int pid; if( __rkusb_write_enable() ) { int max_len; if( DEV_OFFSET(dev) >= 0xc0000000 ) { rkusb_normal_data_xfer( dev , NULL ); return RKUSB_CB_OK_NONE; } max_len = DEV_RWBUF_LENGTH( dev ); if( max_len < DEV_LENGTH(dev) ) { return RKUSB_CB_FAILD; } pid = DEV_PID( dev ); if( pid ) { dev->slave_task = find_task_by_pid( pid ); if(!dev->slave_task ) return RKUSB_CB_FAILD; //rk28printk("%s::pid=%d,task=%s\n" , __func__ , pid , dev->slave_task->comm ); } else { dev->slave_task = current ; } /* bakeup real offset and length */ dev->private_tmp = (void*)DEV_OFFSET(dev); dev->buf_nfill = DEV_LENGTH(dev); __rkusb_set_dest_or_source( dev , __rkusb_rwbuffer_start( dev ) ); rkusb_normal_data_xfer( dev , rkusb_write_sdram_cb); return RKUSB_CB_OK_NONE; } return RKUSB_CB_FAILD; }
static int rkusb_rw_file_cb( struct rkusb_dev *dev ) { FILE_INFO *fi = rkusb_xfer_cmd_valid( dev ); int data_in = DEV_DATA_IN(dev); int actual = dev->req_out->actual; if( data_in ) actual = dev->req_in->actual; DEV_LENGTH( dev ) -= actual; //rk28printk("%s::remain len=0x%x,actual=0x%x\n" ,__func__, DEV_LENGTH(dev) ,actual ); #if 0 if( DEV_LENGTH(dev) > 0 ) { if(!fi || (fi->error && fi->error != - FI_ERR_CLEAR) ) { /* error !*/ __rkusb_set_dest_or_source( dev , rwb->buf ); rkusb_normal_data_xfer_max_size( dev , rkusb_rw_file_cb , 0X40000000 ); return RKUSB_CB_FAILD_CSW; } } #endif /* 20091222,HSL@RK,write last packed */ if( FI_WRITE(fi) ) { dev->buf_filled = 1; } else { dev->buf_filled = 0; } rkusb_wakeup_thread( dev ); return RKUSB_CB_OK_NONE; }
static int rkusb_reinit_req( struct rkusb_dev *dev,struct usb_ep* ep_in,struct usb_ep* ep_out ) { __rkusb_free_ep_req( dev->ep_in, dev->req_in ); if( !ep_in ) return 0; dev->req_in = __rkusb_init_ep_req(dev, ep_in); dev->ep_in = ep_in; if( !dev->req_in ) return -ENOMEM; dev->req_in->complete = rkusb_complete_in; #if 0 buf = __rkusb_free_ep_req( dev->ep_out, dev->req_out); dev->req_out = __rkusb_init_ep_req(dev, ep_out , buf ); dev->ep_out = ep_out; if( !dev->req_out ) { if( buf ) kfree( buf ); buf = __rkusb_free_ep_req( dev->ep_in, dev->req_in ); if( buf ) kfree( buf ); return -ENOMEM; } dev->req_out->complete = rkusb_complete_out; DEV_LENGTH(dev) = RKUSB_BULK_CB_WRAP_LEN; rkusb_get_cb( dev , DEV_LENGTH(dev) ); #endif return 0; }
static int rkusb_xfer_file_path( struct rkusb_dev *dev ) { if( DEV_LENGTH(dev) < sizeof(FILE_INFO) || DEV_LENGTH(dev) > RKUSB_BUFFER_SIZE ) { return RKUSB_CB_FAILD; } rkusb_normal_data_xfer( dev , rkusb_xfer_file_path_cb ); return RKUSB_CB_OK_NONE; }
static int rkusb_xfer_read_filesize( struct rkusb_dev *dev ) { FILE_INFO *fi = rkusb_xfer_cmd_valid( dev ); if( !fi || DEV_LENGTH(dev) < sizeof(unsigned long ) ) { rkusb_xfer_error( fi , dev , -FI_ERR_CLEAR); return RKUSB_CB_FAILD; } rk28printk("read file size =0x%lx,trans len=%d\n" , fi->file_size , DEV_LENGTH(dev)) rkusb_normal_data_xfer_onetime(dev , &fi->file_size); return RKUSB_CB_OK_NONE; }
static int rkusb_get_lastcmd_result( struct rkusb_dev *dev ) { if( DEV_LENGTH(dev) != RKUSB_RESULT_LEN ) return RKUSB_CB_FAILD; rkusb_normal_data_xfer_onetime( dev , &dev->cr ); return RKUSB_CB_OK_NONE; }
/* * 20100108,HSL@RK,new r/w sdram code. if not kernel space,read at thread one time. */ static int rkusb_do_read_sdram( struct rkusb_dev *dev ) { int r; char *dest = __rkusb_rwbuffer_start( dev ); #if 0 r= copy_from_user(dest , (void __user *) DEV_OFFSET( dev ), DEV_LENGTH(dev) ); #else r = access_process_vm(dev->slave_task, DEV_OFFSET( dev ), dest , DEV_LENGTH(dev) , 0); #endif rk28printk("%s::read task=%s,lba=0x%x,len=%d\n" , __func__ , dev->slave_task->comm, DEV_OFFSET( dev ) , DEV_LENGTH(dev)); if( r != DEV_LENGTH(dev)) { rk28printk("get user data error,task=%s,lba=0x%x,r=0x%x\n" , dev->slave_task->comm,DEV_OFFSET( dev ) , r); } rkusb_normal_data_xfer_onetime( dev , dest ); return RKUSB_CB_OK_NONE; }
static int rkusb_xfer_file( struct rkusb_dev *dev ) { FILE_INFO *fi = rkusb_xfer_cmd_valid( dev ); if( !fi || DEV_LENGTH(dev) > fi->file_size || DEV_OFFSET(dev) > fi->file_size || DEV_OFFSET(dev)+DEV_LENGTH(dev)>fi->file_size ) { rkusb_xfer_error( fi , dev , -EINVAL); return RKUSB_CB_FAILD; } #if 0 if( FI_WRITE(fi) ) { /* write */ dev->phase = RKUSB_PHASE_DATAOUT; } else { dev->phase = RKUSB_PHASE_DATAIN; } #endif rkusb_wakeup_thread( dev ); return RKUSB_CB_OK_NONE; }
/* * for cmd must run at task env.not irq env. */ static int rkusb_task_cmd( struct rkusb_dev *dev ) { int r = RKUSB_CB_FAILD; switch( DEV_FUNC(dev )) { case FUNC_TASKF_PING: /*20100108,HSL@RK, for get cb at complete out.*/ DEV_LENGTH(dev) = RKUSB_BULK_CB_WRAP_LEN; r= RKUSB_CB_OK_NONE; break; default: break; } if( r != RKUSB_CB_FAILD ) rkusb_wakeup_thread( dev ); return r; }
static int rkusb_get_task_cmd( struct rkusb_dev *dev ) { struct task_struct *p; int pid = DEV_OFFSET(dev); if( DEV_LENGTH(dev) > DEV_RWBUF_LENGTH( dev ) ) return RKUSB_CB_FAILD; if( pid == 0 ) p = current ; else { p = find_task_by_pid( pid ); if( !p ) return RKUSB_CB_FAILD; } dev->slave_task = p; return RKUSB_CB_OK_NONE; }
static int rkusb_xfer_file_path_cb( struct rkusb_dev *dev ) { FILE_INFO *fi = (FILE_INFO*)dev->req_out->buf; if( !fi || FI_INVALID(fi) || fi->size < sizeof(FILE_INFO) ) return RKUSB_CB_FAILD_CSW; if( FI_WRITE(fi) && fi->file_size == 0 ) /* write */ return RKUSB_CB_FAILD_CSW; fi = (FILE_INFO*)kmalloc( sizeof( FILE_INFO ), GFP_ATOMIC ); memcpy( fi , dev->req_out->buf , dev->req_out->actual ); fi->file = fi->private_data = NULL; fi->error = 0; if( !FI_WRITE(fi) ) { fi->file_size = 0; } dev->private_tmp = fi; /*20100112,HSL@RK, for get cb at complete out.*/ DEV_LENGTH(dev) = RKUSB_BULK_CB_WRAP_LEN; rkusb_wakeup_thread( dev ); return RKUSB_CB_OK_NONE; }
static int rkusb_do_thread_cmd( struct rkusb_dev *dev ) { rk28printk("rkusb thread cmd = 0x%x,func=0x%x,len=%d\n" , DEV_CMD(dev),DEV_FUNC(dev) , DEV_LENGTH(dev)); switch( DEV_CMD(dev)) { #if RKUSB_XFILE case K_FW_XFERFILE: { FILE_INFO *fi = rkusb_xfer_cmd_valid( dev ); if( !fi ) { rk28printk("invalid FILE_INFO for K_FW_XFERFILE[0x%x]\n" , K_FW_XFERFILE ); break; } switch( DEV_FUNC(dev )) { case FUNC_XFER_FILE_PATH: rkusb_file_path( dev ); break; case FUNC_RFILE_DATA: case FUNC_WFILE_DATA: rkusb_xfer_file_task( dev ); break; default: break; } if( fi->error ) rkusb_xfer_free_fi( dev ); } break; #endif /* RKUSB_XFILE */ case K_FW_TASKFUN: rkusb_do_task_cmd( dev ); break; case K_FW_SDRAM_READ_10: rkusb_do_read_sdram( dev ); break; case K_FW_SDRAM_WRITE_10: rkusb_do_write_sdram( dev ); break; case K_FW_FUNCALL: rkusb_do_func_call( dev ); break; case K_FW_USBCMD : if(FUNC_UCMD_RKUSBVER== DEV_FUNC(dev ) && (DEV_OFFSET(dev) == ECC_SWITCH_MSC || DEV_OFFSET(dev) == ECC_RESET) ) { char cmd[32]; char *p=(char *)DEV_INREQ_BUF(dev); strncpy( cmd , p , sizeof(cmd) ); rkusb_send_csw( dev , RKUSB_STATUS_PASS ); mdelay(10); sys_sync(); kernel_restart( cmd ); } else { rkusb_send_csw( dev , RKUSB_STATUS_FAIL ); } break; default: return -ENOTSUPP; break; } return 0; }
static int rkusb_read_sdram( struct rkusb_dev *dev ) { int pid; if( __rkusb_read_enable() ) { if( DEV_OFFSET(dev) >= 0xc0000000 ) { rkusb_normal_data_xfer( dev , NULL ); return RKUSB_CB_OK_NONE; } pid = DEV_PID( dev ); if( pid ) { dev->slave_task = find_task_by_pid( pid ); if(!dev->slave_task ) return RKUSB_CB_FAILD; //rk28printk("%s::pid=%d,task=%s\n" , __func__ , pid , dev->slave_task->comm ); } else { dev->slave_task = current ; } if( dev->slave_task == current ){ char *dest = __rkusb_rwbuffer_start( dev ); int n = copy_from_user((void*)dest, (const void __user*)DEV_OFFSET(dev), DEV_LENGTH(dev)); if( !n ) { rkusb_normal_data_xfer_onetime( dev , dest ); return RKUSB_CB_OK_NONE; } else return RKUSB_CB_FAILD; } rkusb_wakeup_thread( dev ); return RKUSB_CB_OK_NONE; } return RKUSB_CB_FAILD; }
/* * 20091221,add file offset for large file. */ static int rkusb_xfer_file_task( struct rkusb_dev *dev ) { int nread; int mount; int total; int real_tranfs; FILE_INFO *fi = (FILE_INFO*)dev->private_tmp; char *buf_bak; loff_t pos = DEV_OFFSET(dev); real_tranfs = mount = __rkusb_rwbuffer_end(dev) -__rkusb_rwbuffer_start(dev); dev->buf_filled = 0; fi->error = 0; total = 0; if( FI_WRITE(fi) ) buf_bak = rkusb_reset_req_buf(dev->req_out,dev->buf); else buf_bak = rkusb_reset_req_buf(dev->req_in,dev->buf);; for(; ;) { if (signal_pending(current)) break; if( FI_WRITE(fi) ) { if( DEV_LENGTH( dev ) < mount ) { //mount = DEV_LENGTH( dev ) ; real_tranfs = DEV_LENGTH( dev ) ; //rk28printk("vfs r/w last pack , len =0x%x\n" , real_tranfs ); } //rk28printk("total write=0x%x,remain=0x%x,file size=0x%lx,mount=0x%x\n" , // total , DEV_LENGTH(dev) , fi->file_size , mount ); #if 1 rkusb_get_data_buffer( dev , mount , rkusb_rw_file_cb ); #else //__rkusb_set_dest_or_source( dev , rwb->buf ); rkusb_normal_data_xfer_max_size( dev , rkusb_rw_file_cb , mount); #endif while( !dev->buf_filled ) { rkusb_sleep_thread( dev ); } if( fi->error ) break; nread = vfs_write(fi->file, dev->buf , real_tranfs ,&pos); if( nread < 0 ) { rk28printk("vfs write failed , ret =%d\n" , nread ); fi->error = nread; } else { dev->buf_filled = 0; total += nread; } if( DEV_LENGTH( dev ) == 0 ) break; } else { //rk28printk("total read=0x%x,remain=0x%x,file size=0x%lx,mount=0x%x\n" , // total , DEV_LENGTH(dev) , fi->file_size , mount ); while( dev->buf_filled ) { rkusb_sleep_thread( dev ); } if( fi->error ) break; if( DEV_LENGTH( dev ) == 0 ) break; nread = vfs_read(fi->file, dev->buf , real_tranfs ,&pos); if( nread < 0 ) { rk28printk("vfs read failed , ret =%d\n" , nread ); fi->error = nread; } else { dev->buf_filled = 1; total += nread; if( nread < real_tranfs && total < fi->file_size ) { /* 20100115,HSL@RK,set 0 at pc tools */ //rwb->buf[nread] = 0; //if( real_tranfs - nread > 5 ) // strcpy(rwb->buf+nread+1,"@#$"); nread = real_tranfs; } } //rk28printk("read finish,nread=0x%x,start transfer,real transfer=0x%x\n" , // nread , real_tranfs ); #if 1 rkusb_send_data_buffer( dev , nread , rkusb_rw_file_cb ); #else __rkusb_set_dest_or_source( dev , rwb->buf ); rkusb_normal_data_xfer_max_size( dev , rkusb_rw_file_cb , mount); #endif } } rk28printk("file transfer finish,error=%d\n" , fi->error ); if( FI_WRITE(fi) ) { rkusb_reset_req_buf(dev->req_out , buf_bak); rkusb_get_cb( dev , RKUSB_BULK_CB_WRAP_LEN ); } else rkusb_reset_req_buf(dev->req_in , buf_bak); /* close file , free FILE_INFO */ if( !fi->error ) { fi->error = - FI_ERR_CLEAR; rkusb_send_csw( dev , RKUSB_STATUS_PASS ); } else { rkusb_send_csw( dev , RKUSB_STATUS_FAIL ); } return 0; }
static int rkusb_command( struct rkusb_dev *dev ) { int r= RKUSB_CB_FAILD; //dev->cb.DataTransferLength = __be32_to_cpu( dev->cb.DataTransferLength ); //dev->cb.Lba = __be32_to_cpu( dev->cb.Lba ); //dev->cb.pid = __be16_to_cpu( dev->cb.pid ); rkusb_print_cb( dev ); if( DEV_LENGTH(dev) > dev->req_buf_length ){ rk28printk("data length[0x%x] > limit[0x%x]\n" , DEV_LENGTH(dev),dev->req_buf_length); DEV_LENGTH(dev) = dev->req_buf_length; } //dev->thread_task->mm = NULL; dev->slave_task = NULL; switch ( DEV_CMD(dev) ) { case K_FW_GETRESULT: r = rkusb_get_lastcmd_result( dev ); break; case K_FW_GETLOG: r = rkusb_get_log( dev ); break; case K_FW_SETLOG: r = rkusb_set_log( dev ); break; case K_FW_TRACE: r = rkusb_do_trace( dev ); break; case K_FW_USBCMD: r = rkusb_usb_command( dev ); break; case K_FW_XFERFILE: r = rkusb_do_xfer_file( dev ); break; case K_FW_FUNCALL: r = rkusb_function_call( dev ); break; case K_FW_SDRAM_READ_10: r = rkusb_read_sdram( dev ); break; case K_FW_SDRAM_WRITE_10: r = rkusb_write_sdram( dev ); break; case K_FW_GETSYMB: r = rkusb_get_symbol( dev ); break; case K_FW_TASKFUN: r = rkusb_task_cmd( dev ); break; default: return RKUSB_NOT_HANDLED; } if( RKUSB_CB_FAILD == r ) { /* 20100330,HSL@RK,for failed cmd,must handle it */ DEV_OFFSET(dev) = 0; rkusb_normal_data_xfer( dev , rkusb_failed_cb ); return 0 ; /* RKUSB_NOT_HANDLED;*/ } else if( RKUSB_CB_OK_CSW == r ) rkusb_send_csw( dev , RKUSB_STATUS_PASS ); else if( RKUSB_CB_FAILD_CSW == r ) rkusb_send_csw( dev , RKUSB_STATUS_FAIL); return 0; }
static int rkusb_write_sdram_cb( struct rkusb_dev *dev ) { DEV_LENGTH(dev) = RKUSB_BULK_CB_WRAP_LEN; rkusb_wakeup_thread( dev ); return RKUSB_CB_OK_NONE; }
static int rkusb_usb_command( struct rkusb_dev *dev ) { int r = RKUSB_CB_FAILD; rk28printk("%s::func=%d,len=%d\n" , __func__ , DEV_FUNC(dev),DEV_LENGTH(dev)); switch( DEV_FUNC(dev) ) { case FUNC_UCMD_DEVREADY: r = RKUSB_CB_OK_CSW; break; case FUNC_UCMD_DISCONNECTMSC: rk28_msc_switch( 0 ); r = RKUSB_CB_OK_CSW; break; case FUNC_UCMD_SYSTEMINFO: { unsigned int off_len[2]; off_len[0] = (unsigned int)system_type; off_len[1] = strlen(system_type)+1; rkusb_normal_data_xfer_onetime(dev , off_len ); r = RKUSB_CB_OK_NONE; } break; case FUNC_UCMD_RESTART: rk28printk("get restart cmd,lun=%d\n" , DEV_LUN(dev)); if( DEV_LUN(dev) == 0 ) { /* normal restart */ rk28_restart(0); } else if( DEV_LUN(dev) == 1 ) { /* to loader rkusb */ rk28_restart(1); } break; case FUNC_UCMD_GETVERSION: r = rkusb_ucmd_get_version( dev ); break; case FUNC_UCMD_GETCHIPINFO: { unsigned int off_len[2]; off_len[1] = kld_get_tag_data( 0X524B0000 , (void**)&off_len ); rkusb_normal_data_xfer_onetime(dev , off_len ); r = RKUSB_CB_OK_NONE; } break; case FUNC_UCMD_GETSN: { unsigned int off_len[2]; off_len[1] = kld_get_tag_data( 0X524B0006 , (void**)&off_len ); rkusb_normal_data_xfer_onetime(dev , off_len ); r = RKUSB_CB_OK_NONE; } break; case FUNC_UCMD_DEBUGINFO: { RKDEBUG_INFO *dbi = DEV_FAST_ALLOC(dev,RKDEBUG_INFO); dbi->size = sizeof(RKDEBUG_INFO); dbi->adb_support = adb_support; dbi->dbg_level = __rkusb_write_enable(dev)?2:(__rkusb_read_enable(dev)?1:0); dbi->tr_length = dev->req_buf_length; dbi->save_length = dev->buf_length; dbi->save_buf = (unsigned long)__rkusb_rwbuffer_start(dev); if( dev->fsg ) strcpy(dbi->cur_device,"msc"); else strcpy(dbi->cur_device,"adb"); strcpy( dbi->cur_version,RKUSB_KVERSION); #if 0 dbi->cmds[0]=K_FW_SDRAM_READ_10; dbi->cmds[1]=K_FW_SDRAM_WRITE_10; dbi->cmds[2]=K_FW_TRACE; dbi->cmds[3]=K_FW_GETLOG; dbi->cmds[4]=K_FW_FUNCALL; dbi->cmds[5]=K_FW_GETSYMB; dbi->cmds[6]=K_FW_GETRESULT; dbi->cmds[7]=K_FW_USBCMD; #endif rkusb_normal_data_xfer_onetime(dev , dbi ); r = RKUSB_CB_OK_NONE; } break; case FUNC_UCMD_OPENADB: { /* lun:0 close,1: open */ adb_function_enable(DEV_LUN(dev)); usb_vbus_status = 0; /* force to reconnect! */ r = RKUSB_CB_OK_CSW; } break; default: break ; } return r; }