//------------------------------------------------------------------- // wrapfix.c Revision of driver 'read()' method // // Here is a revised version of the 'read()' function for our // previous character-mode device-driver prototypes developed // for the RealTek 8139 network controllers in our University // workstations in the Kudlick Classroom. Prior versions did // not properly copy data in the network controller's Receive // Buffer in cases where the receivd packet "wrapped around." // // programmer: ALLAN CRUSE // written on: 01 MAY 2005 //------------------------------------------------------------------- #include // for init_module() #include // for wait_event_interuptible() #include // for inb(), outb() #include // for copy_to_user() #define RBUFSZ (8<<10) // Length of Read Buffer (8KB) #define WBUFSZ (8<<10) // Length of Write Buffer (8KB) void *kmem; // virtual address of TX/RX buffers int iobase; // base-address of device i/o ports wait_queue_head_t rx_wq; // waitqueue head for sleep/wakeup ssize_t my_read( struct file *file, char *buf, size_t len, loff_t *pos ) { unsigned int offset, header, status, length, nextrx; unsigned int pktlen, begoff, endoff, retlen, dowrap, more; char *rxbuf = (char*)kmem + WBUFSZ; // return immediately in non-blocking mode if no data is ready if (( file->f_flags & O_NONBLOCK )&&( inb( iobase + 0x37 )&1 )) return -EAGAIN; // sleep until the Receive Buffer is no longer empty wait_event_interruptible( rx_wq, (inb( iobase + 0x37 )&1) == 0 ); if ( signal_pending( current ) ) return -EINTR; // Reimplementation of our packet-read algorithm (05/01/2005) // rxbuf = virtual-address for RBStart // offset = offset to the packet-header offset = ( inw( iobase + 0x38 ) + 16 ) % RBUFSZ; header = *(unsigned int*)(rxbuf+offset);// the frame-header status = (header >> 0 )& 0xFFFF; // loword of header length = (header >> 16 )& 0xFFFF; // hiword of header pktlen = length - 4; // omitting the CRC retlen = ( len < pktlen ) ? len : pktlen; // bytes to copy // we must copy two contiguous segments in case the packet wraps begoff = ( offset + 4 )%RBUFSZ; // offset to beginning of packet endoff = ( begoff + retlen ); // offset to end-of-data-to-copy dowrap = ( endoff > RBUFSZ ); // data wraps in circular buffer if ( !dowrap ) { char *src = rxbuf + begoff; char *dst = buf; more = copy_to_user( dst, src, retlen ); } else { int len1 = RBUFSZ - begoff; int len2 = endoff - RBUFSZ; char *src1 = rxbuf + begoff; char *dst1 = buf; char *src2 = rxbuf; char *dst2 = buf + len1; more = 0; more += copy_to_user( dst1, src1, len1 ); more += copy_to_user( dst2, src2, len2 ); } // update the Receive Buffer's 'guard' register (i.e., CAPR) nextrx = ( offset + 4 + ((length + 3)&~3)) + (RBUFSZ - 16); nextrx %= RBUFSZ; // (modular arithmetic) outw( nextrx, iobase + 0x38 ); // update CAPR register if ( more ) return -EFAULT; // more-to-copy? error! // advance the file position and report count of bytes copied *pos += retlen; return retlen; }