• Keine Ergebnisse gefunden

Allocating Buffer Space

Im Dokument INTER ACTIVE (Seite 77-82)

As mentioned in the discussion on the driver read() and write() routines, drivers may require buffers for passing data around. The following utility rou-tines in the UNIX System provide buffer space.

Buffer Pool

The UNIX System provides a set of buffers that are normally used for file system I/O, but they can be "borrowed" by drivers if they follow the rules outlined here. The driver must include the header file sysjbuf.h. The size of UNIX System V /386 buffers is 1024 bytes. The functions that drivers may use to manipulate the buffers are

1. struct buf *geteblk();

Allocates a buffer and returns a pointer to a buffer header that, in tum, points to the data buffer.

2. brelse(bp) struct buf *bp;

Releases a previously allocated buffer.

3. iowait(bp) struet buf *bp;

Sleeps on the buffer awaiting an event, such as completion of I/O.

4. iodone(bp) struet buf *bp;

Awakens a process sleeping via iowait().

5. clrbuf(bp) struet buf *bp;

Clears the contents of the buffer (sets every byte in the buffer to 0) whose header is the pointer bp.

The driver may access the buffer header field b--Ilags to access buffer state flags and the field b_un.b~ddr to get the address where the data buffer resides. Acceptable flags to use in the b--Ilags field are

1. B_WRITE when writing data from the buffer to the device.

3·38 ISDG

2. B_READ when reading data from the device.

3. B_DONE, set by the function iodoneO, to indicate that the I/O opera-tion has completed.

4. B-ERROR to indicate an error in use of the buffer.

S. B_BUSY to lock the buffer and prevent other processes from accessing the buffer. Use of the B_BUSY flag prevents other processes from accessing the buffer if they first check the flag to see if it is busy.

while (bp->b_flags &. B_BOSY) sleep(bp, mIPRI);

bp->b_flags 1= B_BOSY;

6. B_WANTED to indicate that a process is sleeping awaiting the buffer.

The function brelseO clears the flags B_WANTED and B_BUSY, and the function geteblkO sets the B_BUSY flag. It is best to "or" and

"and" the flags in, rather than just setting them.

Here is an example of the use of buffers in a tape driver:

DEVICE DRIVERS 3·39

tapecntl(dev, flag, opoode, arg1, arg2) {

}

Clists

register struct buf *bp;

register int rcode;

bp

=

(struct buf *) geteblk();

1* CNl'L flag is used to umcate this is a control buffer *1 bp->b_flags 1= B_CNl'L;

1* set async flag so buffer will be released *1 i f (flag

==

FNOELAY)

bp->b_flags 1 = B_ASYr<C;

bp->b_dev = (Ml'O«8) ldev;

tapestrategy(bp);

rcode = 0;

if (flag I = FtIDErAY) { iowait(bp) ;

if (bp->b_flags&B_ERROR) rcode = -1;

bp->b_flags &= -B_CNl'L;

brelse (bp) ; }

retmn(roode) ;

By including the header file sysjtty.h, drivers can use clists and cblocks (generic names for character lists and character blocks) to buffer small bursts of data from slow-speed devices. Drivers should use clists if they are interested in character by character processing of data, as in terminal drivers.

The only field in the cblock that a driver may access directly is char c-delim;

The driver can use it to record status of the cblock. The size of the cblock data buffer is CLSIZE bytes, usually set between 64 and 256 bytes, as com-pared to the buffer sizes of 1024 bytes.

3-40 ISDG

The driver should not access fields in the dist or cblock data structure (except for c_delim) unless it uses the following routines:

1. getc(p) struct dist *p;

Returns a character (really an int) from the dist pointed to by p, but it returns -1 if the dist is empty.

2. putc(c, p) char c;

struct dist *p;

Places the character at the end of the dist pointed to by p. If system resources are exhausted, putc returns -1 (error); otherwise, it returns O.

3. struct cblock *getcfO

Returns a new cblock to the caller, returning NULL if no cblocks are available in the system.

4. putcf(cp) struct cblock *cp;

Returns the cblock pointed to by cp to the system.

5. struct cblock *getcb(p) struct dist *p;

Returns a pointer to the first cblock on the dist p, but it returns NULL if the dist is empty.

6. putcb(cp, p) struct cblock *cp; struct dist *p;

Places the cblock pointed to by cp on the end of the dist p.

7. getcbp(p, cp, n)

Copies characters from the specified dist, p, to the buffer addressed by the cp argument. cp is a char * addressing the buffer to which the characters are to be copied. n is the number of characters to be copied. getcbp must be called at sp160. This routine returns the number of characters actually copied, which is less than or equal to n.

8. putcbp(p, cp, n)

Copies characters from a buffer to the dist given as an argument. p is a struct dist *. cp is a char *, which addresses the buffer. n is the

DEVICE DRIVERS 3-41

number of characters to be copied to the clist. putcbp must be called at sp160.

Here is an example of the use of clists, taken from a routine to read the

"canonical" input from a terminal (note that the routine is not given here in its entirety). The tty structure contains the clists Lcanq and Lrawq:

canan(tp)

register stru.ct tty *tp;

{

}

register struct cblock *cp;

splS() ;

i f (tp->t_ra'lllq.c_cf

==

NULL)

tp->t_delct

=

0;

while (tp->t_delct

==

0) {

}

if( 1 (tp->t_state&CARR_OO) II (u.u_:fm:xie&mDELAY» { splO() ;

return;

}

tp->t_state 1= IASLP;

sleep( (caddr_t)&.tp->t_ra'lllq, 'l'TIPRI);

if(!(tp->t_lflag&ICANON» { tp->t_canq = tp->t_ra'lllq;

tp->t_ra'lllq = ttnulq;

tp->t_delct = 0;

} splO() ;

splO();

return;

while ( (cp = getcb(&.tp->tJa'lllq» 1= NULL) { pltcb(cp, &.tp->t_canq);

if(cp->c_delim) break;

3-42 ISDG

UNIX System V /386 Installable Driver

Im Dokument INTER ACTIVE (Seite 77-82)