📄 usersu.c
字号:
ritorno=usb_submit_urb(urb, KMALLOC_FLAG); if (ritorno==0) nurb_submitted++; } /* if urb allocated.*/ } return ritorno;}/* Stop when deallocating first endpoint. * * ING USC Ordine Probe Ordine Disconnect * 0x81 0x00 0x81 0x81 * 0x82 0x02 0x02, 0x82 0x02, 0x82 * * This is because in 0x81 0x00, 0x00 is already probed by usbcore. * Now seem !2be a problem. */static int BuffRead_disco(int blockId, struct usb_endpoint_descriptor* endpoint) { stop_submit=1; if (blocks[blockId]) { FsEntryT* data; char* nome; char *buf; struct BuffReadT* br; struct dataQ_T *dq; void* context; data = (FsEntryT*) blocks[blockId]; nome = NULL; buf = NULL; context = NULL; br = NULL; dq = NULL; br = (struct BuffReadT*) data->data; if (br) buf=br->dq.data; if (br) context = br->dq.context; if (buf) kfree(buf); if (br) kfree(br); usbdo_deleteFile(endpoint->bmAttributes); if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)==USB_DIR_IN) { struct urb *urb; char* bf; urb = (struct urb*) context; bf = NULL; PRINT("Stopping&deallocating input urb..."); if (urb) bf = urb->transfer_buffer; usb_unlink_urb(urb); usb_free_urb(urb); if (bf) usb_buffer_free(0,0,bf,0); } blocks[blockId] = NULL; } return 0;}/* This object simply help to produce a 'continuous' stream of data. * Any decoder will be in user space or as hierarchical file operation. * * Internal organization remember c++ stl io: there is a method, perhaps * underflow(), that c++ engine call when strbuf have no data. * * Instead of overload stateInfo, is better preferred new object oriented * interface container_of() etc. stateInfo exist for simplify little work. */struct ioStreamT { /* Related to a places of bytes:*/ struct urbDataT places[ISOC_URBSPRE]; /* n of urb per direction.*/ int curPlace; /* Only need if >1 place. */ /* To 'immediately' wake-up user world when space/data available.*/ struct semaphore wait4data; int (*underflow)(struct ioStreamT *i); atomic_t mutuaEsclusione; int lastErr; union {int bytesRx; int bytesTx;}; /* Statistical info.*/ union {int nOfNotsync_read; int nOfNotsync_write;}; int nOfNotsync_intr; int nOfUrbCompleted; /* Statistical info, status oriented.*/ int nOfSubmit;};struct DoubleBuffT { struct ioStreamT istream; struct ioStreamT ostream;};void DoubleBuff_complete(struct urb *urb,struct pt_regs* regs) { int ritorno,l,len; static int lastLen = -1; static int lastRet = 1; static int howmRep = 0; ritorno = 0; len = 0; nurb_submitted--; for (l=0; l<urb->number_of_packets; l++) { ritorno = ritorno?ritorno:urb->iso_frame_desc[l].status; len += urb->iso_frame_desc[l].actual_length; } if (ritorno == lastRet && len == lastLen) {/* if (log && howmRep==0) {PRINT("isoc_complete(len,status)=(%d,%d).",len,ritorno);}*/ if (log && howmRep==1) {PRINT("...");} if (howmRep<=1) howmRep++; } else { if (log) {PRINT("isoc_complete(len,status)=(%d,%d).",len,ritorno);} lastLen = len; lastRet = ritorno; howmRep = 1; } if (!stop_submit) { /* wake up user only if (status,len)!=(0,0), to avoid heavy load on CPU * - module become unremovable, * - process cat become unkillable. * * If (!data present) & (!error) silently resubmit_urb() * else * Stop & wakeup to request attention2who manage bytes. */ struct ioStreamT* iost = (struct ioStreamT*) urb->context; iost->nOfSubmit--; iost->nOfUrbCompleted++; if (ritorno==0 && len==0) { urb->dev=dev; urb->status=0; ritorno=usb_submit_urb(urb, KMALLOC_FLAG); if (ritorno==0) { nurb_submitted++; iost->nOfSubmit++; } else { PRINT("usb_submit()=NOK!(ret=%d)",ritorno); } } else { if (ritorno==0) iost->bytesRx += len; up(&(iost->wait4data)); } iost->lastErr = ritorno; } else { PRINT("shutdown."); }}#if 0/* return * 0 if ok, * <0 if some error. * * If called by complete, queue urb|data. * */void complete_isoc2(struct urb *urb, struct pt_regs *regs) { int ritorno=0; struct ioStreamT *ioSt; int diri; nurb_submitted--; diri=usb_pipein(urb->pipe); ioSt=(struct ioStreamT*) urb->context; ioSt->nOfUrbCompleted++; if (stop_submit>0) { /*usu_device.intIsStopped--;*/ ritorno=-ENODEV; } else if (!urb) { ritorno=-EFAULT; } else { /* 1) Acquire lock. If fail => return, * the owner are working also4us. Ret true if count reach 0.*/ if (!atomic_dec_and_test(&ioSt->mutuaEsclusione)) { ioSt->nOfNotsync_intr++; ritorno=-EAGAIN; } if (ritorno==0) { /* iStream: * 2-a) if (active=EMPTY)*(backg=EMPTY)*(urb=DONE) => start urb * 2-b) if (active=EMPTY)*(backg=FULL )*(urb=DONE) => swap,signal,start urb. * urb state={DONE, RUNNING, ERROR} * * oStream: * active=FULL = curP==curL * back =EMPTY= status=0 * 2-a) if (active=FULL )*(backg=EMPTY)*(urb=DONE) => start urb.*/ if (ioSt->curL==ioSt->curP && urb->status==0) { int isocLen,l; isocLen=0; for (l=0; l<urb->number_of_packets; l++) isocLen+=urb->iso_frame_desc[l].actual_length;/* iStream.curL=ISOC_NUMBOfP*ISOC_BYTESxP;*/ switch (isocLen) { case ISOC_NUMBOfP*ISOC_BYTESxP: { for (l=0; l<urb->number_of_packets; l++) urb->iso_frame_desc[l].actual_length=0; } /* Called much probably by read()/write().*/ case 0: { if ((diri && isocLen) || !diri) { ioSt->nOfSwap++; urb->transfer_buffer=ioSt->curAct; ioSt->curAct=ioSt->curBac; ioSt->curBac=urb->transfer_buffer; ioSt->curP=0; /* All this hypo is in order2avoid unneeded signal/wait * * Read case: * if isocLen==0=> must !signal: * - called by Read() * - is the first time, * - urb start later, * - Read()'ll immediatly call wait() * * Write case: * However signal: * - we know that other Write() must wait * - we don't know if current Write() has * consumend len>0 so return without wait * Sol: now we take 2 (signal,wait) */ up(&ioSt->wait4data); } /*} {*/ urb->dev=dev; urb->status=0; ritorno=usb_submit_urb(urb,KMALLOC_FLAG); break; } default: {ritorno=-EIO; break;} } } } atomic_inc(&ioSt->mutuaEsclusione); } if (ritorno<0) { err("complete_isoc2(): ret %d.\n",ritorno); if (ritorno!=-EAGAIN) ioSt->lastErr=ritorno; }}#endif/* Return >0 number of bytes. * <0 error code. */int DoubleBuff_read(char* page, unsigned int count, void* data){ int ritorno=0; static int stop_on_err = 1; while (ritorno==0) { /* Only here we start urb.*/ int l; struct ioStreamT* ist = &(((struct DoubleBuffT*) data)->istream); int newCurPlace = -1; /* !valid value: the first submit()Ok will initialize it.*/ int urbRunning = 0; int stopSearch = 0; /* * 1) On urb !running, read() & restart() * * TODO: 1) when there was no more data, here we wait next read() to restart urb. */ for (l=0; (l<ISOC_URBSPRE) && (ritorno<=0 && !stopSearch) ; l++) { struct urbDataT* ud = &(ist->places[(ist->curPlace + l) % ISOC_URBSPRE]); if (log) {PRINT("\n(l=%d,i=%d)",l,(ist->curPlace+l)%ISOC_URBSPRE);} ritorno = readUrbD(ud, page, count); if (log) {PRINT("\nreadUrbd[%d](count=%d)=%d",(ist->curPlace+l)%ISOC_URBSPRE,count,ritorno);} urbRunning = (ritorno == -EINPROGRESS)/* || (ritorno == -EXDEV)*/; stopSearch = (ritorno<0 && stop_on_err) && !urbRunning; /* Dump error on urb.*/ if (ritorno<0 && !urbRunning) { char buf[500]; PRINT("readUrb() found an urb with error(%d).",ritorno); USBDo_dumpUrb(ud->urb,buf,480); buf[480]='\x0'; PRINT("%s",buf); } if (ritorno>0 || urbRunning || stopSearch) { /* do nothing.*/ } else { /* try2submit urb.*/ int k; ud->urb->status = 0; ud->urb->actual_length = 0; for (k=0; k<ud->urb->number_of_packets; k++) { ud->urb->iso_frame_desc[k].status = 0; ud->urb->iso_frame_desc[k].actual_length = 0; } resetUrbD(ud); nurb_submitted++; DoubleBuff_complete(ud->urb,NULL); ritorno = ritorno<0?ritorno:ist->lastErr; if (newCurPlace == -1) newCurPlace = (ist->curPlace + l) % ISOC_URBSPRE; } } /* 2) wait for data if * state(k) ing(k) * ((no data) and (some urb started)) || * (some data) * * if newCurPlace = curPlace mean no urb submitted because: * - have data 2 read() ret>0 * - all urb submitted fail. ret<0 * * ret >0 mean: * - (some urb have data) && (some previous stopped urb,if any, have been successfully restarted). * ret=0 mean: * - (all urb have no data) && (all urb dave been restarted successfully). * ret=-EINPROGRESS if all urb is in progress, so curPlace==newCurPlace => no wait4data => return -EINP. * * ret<0, if (!stop_on_err) mean: * - all urb have error on it/during submit(). * ret<0, if (stop_on_err) mean: * - at least one urb have error on it/during submit(). * * However, if some urb started and have no data, wait for completion. */ if (ritorno == -EINPROGRESS) ritorno = 0; if (ritorno<=0) ritorno=down_interruptible(&(ist->wait4data)); ist->curPlace = newCurPlace==-1? ist->curPlace : newCurPlace; if (log) {PRINT("<while (curPlace,ret)=(%d,%d)>",ist->curPlace, ritorno);} } if (ritorno<0) err("readIsoc2(): ret %d.\n",ritorno); return ritorno;}int DoubleBuff_write(char *buffer, unsigned int count, void *data){ int ritorno=0; static int stop_on_err = 1; while (ritorno==0 && count>0) { /* Only here we start urb.*/ int l; struct ioStreamT* ost = &(((struct DoubleBuffT*) data)->ostream); int newCurPlace = -1; /* !valid value: the first submit()Ok will initialize it.*/ int urbRunning = 0; int stopSearch = 0; /* * 1) On urb !running, write() & if EOB => restart() */ for (l=0; (l<ISOC_URBSPRE) && (ritorno<=0 && !stopSearch) ; l++) { struct urbDataT* ud = &(ost->places[(ost->curPlace + l) % ISOC_URBSPRE]); if (log) {PRINT("\n(l=%d,i=%d)",l,(ost->curPlace+l)%ISOC_URBSPRE);} ritorno = writeUrbD(ud, (char*)buffer, count); if (log) {PRINT("\nwriteUrbd[%d](count=%d)=%d",(ost->curPlace+l)%ISOC_URBSPRE,(int)count,ritorno);} urbRunning = (ritorno == -EINPROGRESS)/* || (ritorno == -EXDEV)*/; stopSearch = (ritorno<0 && stop_on_err) && !urbRunning; /* Dump error on urb.*/ if (ritorno<0 && !urbRunning) { char buf[500]; PRINT("writeUrb() found an urb with error(%d).",ritorno); USBDo_dumpUrb(ud->urb,buf,480); buf[480]='\x0'; PRINT("%s",buf); } if (ritorno>0 || urbRunning || stopSearch) { /* do nothing.*/ } else { /* try2submit urb.*/ int k; ud->urb->status = 0; ud->urb->actual_length = 0; for (k=0; k<ud->urb->number_of_packets; k++) { ud->urb->iso_frame_desc[k].status = 0; ud->urb->iso_frame_desc[k].actual_length = 0; } resetUrbD(ud); nurb_submitted++; DoubleBuff_complete(ud->urb,NULL); ritorno = ritorno<0?ritorno:ost->lastErr; if (newCurPlace == -1) newCurPlace = (ost->curPlace + l + 1) % ISOC_URBSPRE; } } /* 2) wait for data if */ /* All urb is in progress. wait4data.*/ if (ritorno == -EINPROGRESS) ritorno=down_interruptible(&(ost->wait4data)); ost->curPlace = newCurPlace==-1? ost->curPlace : newCurPlace; if (log) {PRINT("<while (curPlace,ret)=(%d,%d)>",ost->curPlace, ritorno);} } if (ritorno<0) err("writeIsoc2(): ret %d.\n",ritorno); return ritorno;} #if 0 while (ritorno==0) { int spaceAv=1; if (!atomic_dec_and_test(&oStream.mutuaEsclusione)) oStream.nOfNotsync_write++; else { /* 1) See howMany bytes we can write.*/ ritorno=oStream.curL-oStream.curP; if (ritorno>count) ritorno=count; /* 2-a) If bytes2Write =>return avail data.*/ if (ritorno>0) { memcpy(oStream.curAct + oStream.curP, buffer, ritorno); oStream.curP+=ritorno; oStream.bytesTx+=ritorno; } spaceAv=(oStream.curL>oStream.curP); } atomic_inc(&oStream.mutuaEsclusione); /* 2-b) Wait if no space av. if (ritorno==0 && count)*/ /* 2-c) If we have fill a place => start urb.*/ if (!spaceAv) { complete_isoc2(usu_device.isoc_usc_urb,0); /* -EINTR if interrupted.*/ ritorno=down_interruptible(&oStream.wait4data); } if (oStream.lastErr<0) ritorno=oStream.lastErr; } if (ritorno<0) err("writeIsoc2(): ret %d.\n",ritorno); return ritorno;}#endifstatic int getUrbSize(int isocFrame) { return (sizeof(struct urb)+isocFrame*sizeof(struct usb_iso_packet_descriptor));}static struct urb* getUrbAddr(struct urb* urbBase, int index, int isocFrame) { char* ret = (char*) urbBase; ret += index*getUrbSize(isocFrame); return (struct urb*) ret;}static int DoubleBuff_probe(int blockId, struct usb_endpoint_descriptor* endpoint) { int ritorno; struct DoubleBuffT* db; int l; ritorno = 0; db = NULL; if (blocks[blockId]==0) { PRINT("set_interface()"); ritorno = usb_set_interface(dev,1,5); if (ritorno == 0) { PRINT("Ok"); db = (struct DoubleBuffT*)kzalloc(sizeof(struct DoubleBuffT),KMALLOC_FLAG); ritorno = -ENOMEM; /* Initialize some data.*/ memset(&(db->istream),0,sizeof(struct ioStreamT)); sema_init(&(db->istream.wait4data),0); atomic_set(&(db->istream.mutuaEsclusione),1); memset(&(db->ostream),0,sizeof(struct ioStreamT)); sema_init(&(db->ostream.wait4data),0); atomic_set(&(db->ostream.mutuaEsclusione),1); } if (db) { /* Create procfs entry. (common code).*/ FsEntryT* data; data = usbdo_createFile(endpoint->bmAttributes); if (data) { data->data = (void*) db; data->read_proc = DoubleBuff_read; data->write_proc = DoubleBuff_write; /*data->owner = THIS_MODULE;*/ } for (l=0; l<ISOC_URBSPRE; l++) { resetUrbD(&(db->istream.places[l])); resetUrbD(&(db->ostream.places[l])); } if (log) { PRINT("i={"); for (l=0; l<ISOC_URBSPRE; l++) { PRINT("%p ",&(db->istream.places[l])); } PRINT("} o={"); for (l=0; l<ISOC_URBSPRE; l++) { PRINT("%p ",&(db->ostream.places[l]));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -