diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 20:52:35 +0000 |
| commit | 46439007cf417cbd9ac8049bb4122c890097a0fa (patch) | |
| tree | 6fdb25e5f3a2b6d5657eb23b35774b631d4d97e4 /man/10/devattach | |
| parent | 37da2899f40661e3e9631e497da8dc59b971cbd0 (diff) | |
20060303-partial
Diffstat (limited to 'man/10/devattach')
| -rw-r--r-- | man/10/devattach | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/man/10/devattach b/man/10/devattach new file mode 100644 index 00000000..718fe9b8 --- /dev/null +++ b/man/10/devattach @@ -0,0 +1,701 @@ +.TH DEVATTACH 10.2 +.SH NAME +devattach, devclone, devdir, devgen, devwalk, devdirread, devstat, devopen, devbread, devbwrite, devcreate, devremove, devwstat, devreset, devinit, devshutdown, openmode \- common device driver support +.SH SYNOPSIS +.nf +.ta \w'\fLBlock* 'u +10n +.B +typedef int +.B +Devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp) +.PP +.B +Chan* devattach(int tc, char *spec) +.PP +.B +Chan* devclone(Chan *c) +.PP +.B +void devdir(Chan *c, Qid qid, char *n, long length, +.B + char *user, long perm, Dir *dp) +.PP +.B +int devgen(Chan *c, char *name, Dirtab *tab, int ntab, +.B + int i, Dir *dp) +.PP +.B +Walkqid* devwalk(Chan *c, Chan *nc, char **name, int nname, +.B + Dirtab *tab, int ntab, Devgen *gen) +.PP +.B +void devstat(Chan *c, uchar *db, int n, Dirtab *tab, +.B + int ntab, Devgen *gen) +.PP +.B +long devdirread(Chan *c, char *d, long n, Dirtab *tab, +.B + int ntab, Devgen *gen) +.PP +.B +Chan* devopen(Chan *c, int omode, Dirtab *tab, +.B + int ntab, Devgen *gen) +.PP +.B +Block* devbread(Chan *c, long n, ulong offset) +.PP +.B +long devbwrite(Chan *c, Block *bp, ulong offset) +.PP +.B +void devcreate(Chan*, char*, int, ulong) +.PP +.B +void devremove(Chan*) +.PP +.B +void devwstat(Chan*, uchar*, int) +.PP +.B +void devreset(void) +.PP +.B +void devinit(void) +.PP +.B +void devshutdown(void) +.PP +.B +int openmode(ulong mode) +.SH DESCRIPTION +Device drivers call these functions to carry out essential tasks and default actions. +They do most of the name space management +for a driver that serves a simple name space +(eg, data and control files), +leaving the driver to concentrate on the device-specific details +of the I/O requests. +More complex drivers also make good use of them at the leaves +of their name space, and to help manage the +.B Chan +structures correctly. +.PP +A device has an associated +.IR type , +represented as a Unicode character (`rune') that identifies the device +inside and outside the kernel. +It appears as the value of the +.B type +field in the +.B Dir +resulting from a +.IR sys-stat (2) +of any file provided by the device. +A device is named outside the kernel using +a path name starting with +.B # +followed by the device character +(eg, +.B c +in +.B #c +for the console). +Any subsequent characters before +the next '/' or end of string is the `device specifier', +interpreted solely by the device itself. +.PP +.I Devattach +returns a new channel representing +the root of the file tree +corresponding to device type +.IR tc , +with device specifier +.IR spec . +It is normally called by a driver's +.I attach +function (see +.IR dev (10.2)). +The +.B qid +for the new channel is +.BR "(Qid){0,0,QTDIR}" , +suitable for a root directory for many devices, but +a device driver is free to change it (provided the +.B QTDIR +bit remains in the +.BR Qid.type ). +.PP +.I Devclone +returns a new channel that is a copy of +.IR c . +An attempt to clone an open channel causes a +.IR panic (10.2). +.PP +The +.L Dir +structure is shown below: +.IP +.EX +typedef +struct Dir +{ + /* system-modified data */ + ushort type; /* server type */ + uint dev; /* server subtype */ + /* file data */ + Qid qid; /* unique id from server */ + ulong mode; /* permissions */ + ulong atime; /* last read time */ + ulong mtime; /* last write time */ + vlong length; /* file length */ + char *name; /* last element of path */ + char *uid; /* owner name */ + char *gid; /* group name */ + char *muid; /* last modifier name */ +} Dir; +.EE +.PP +This +.B Dir +structure corresponds directly to the Limbo +.B Dir +adt described in +.IR sys-stat (2). +.PP +Given a channel and assorted other information, +.I devdir +initialises a Dir structure at +.IR dp . +.I Devdir +supplies the following data itself: +.RS +.TF length +.TP +.B atime +last access time (set to current time) +.TP +.B mtime +last modification time (set to kernel creation date) +.TP +.B gid +group name (set to +.IR eve (10.2)) +.TP +.B length +length in bytes (set to zero, which +is normal for most devices) +.RE +.PD +.PP +Note that +.I devdir +assigns the values of +.I name +and +.I user +directly to fields of +.BI * dp, +and consequently those values must remain valid until the last use of +.BI * dp. +(Sometimes that requires the use of an auxiliary buffer, such as +.BR up->genbuf .) +If channel +.I c +corresponds to a file descriptor on which Styx is served, +.I devdir +sets both the flag bit +.B QTMOUNT +in +.IB dp ->qid.type +and the flag bit +.B DMMOUNT +in +.IB dp ->mode +(see +.I export +in +.IR sys-dial (2) +and +.I mount +in +.IR sys-bind (2)). +.PP +A simple name space can be represented in a driver by an array of +.B Dirtab +structures. +The array is typically static when the names and permissions +are static, but can be dynamically allocated and initialised if required. +The structure of +.B Dirtab +is shown below: +.IP +.EX +typedef +struct Dirtab +{ + char name[KNAMELEN]; + Qid qid; + vlong length; + long perm; +} Dirtab; +.EE +.PP +The name +.RB ` . ' +.I must +appear as the first entry in a +.B Dirtab +if the default +.I devgen +function is used. +On the other hand, the name +.RB ` .. ' +must never appear in a +.B Dirtab +table. +Drivers that support a directory hierarchy must walk up the hierarchy towards +the root when their +.I walk +function receives +.RB ` .. ' +as a file name component. +The name +.RB ` . ' +is never seen by a driver. +.PP +The +.IR devdirread , +.IR devopen , +.IR devstat , +and +.IR devwalk +functions all take a +.I gen +function argument, +of type +.BR Devgen , +which they invoke to retrieve the items in +a +.B Chan +that represents a directory. +.I Gen +takes a channel +.I c +(a directory), +a file +.I name +(which is nil except during +.IR devwalk ), +an array of +.B Dirtab +structures +.I tab +of length +.IR ntab , +and a table index +.IR i . +The functions calling +.I gen +expect it to place the +.IR i 'th +entry in the directory into +.IR \f5*\fPdp . +It should return 1 +if the call was successful, +-1 if +.I i +is beyond the index of the last directory entry, +or 0 if there is no entry at +.IR i , +but there are entries beyond it. +When +.I i +has the special value +.B DEVDOTDOT +then +.I gen +should set +.IR \f5*\fPdp +to reflect the parent of +.IR c ; +if +.I c +is a one-level device directory, then `..' is equivalent to `.'. +Custom implementations of +.I gen +often ignore +.IR devtab , +and instead return their own dynamically generated +set of directory entries from some other source. +Exceptionally, during +.I devwalk +a non-nil +.I name +is provided: it is the name being looked up, and a device-specific +.I gen +can short-circuit the search by returning -1 if the name does not exist, +or filling in +.IR \f5*\fPdp +and returning 1 if it does exist. +.PP +The function +.I devgen +is compatible with +.BR Devgen ; +it returns the +.IR i 'th +entry in +.IR devtab , +and can be used to provide a simple, static +set of directory entries. +.PP +.I Devwalk +walks channel +.I c +to the file in the device named by the path encoded in +.IR name , +which is an array of strings of length +.IR nname . +It provides the interface to +.IR walk (5) +within the kernel, and that specification must be well understood to appreciate +all the nuances of its interface. +Fortunately, in nearly all device drivers, a device's +.I walk +function typically passes its parameters on to +.I devwalk +(adding the device's own +.B Dirtab +array as the the value of +.IR tab ), +and simply returning the result of +.IR devwalk . +.PP +.I Devwalk +walks +.I c +using the given set of names, and if the walk is successful, the +channel +.I nc +will refer to the result of the walk +(specifically, +.IB nc ->qid +is set to the Qid for the file). +If +.I nc +is nil, +.I devwalk +will allocate a new channel itself, that is initially a clone of +.IR c . +As in +.IR walk (5), +.I devwalk +can return a partial result, +represented by +a dynamically allocated value of the following structure: +.IP +.EX +struct Walkqid +{ + Chan *clone; + int nqid; + Qid qid[1]; /* actually nname in length */ +}; +.EE +.PP +The value must be freed after use. +For each element of +.I name , +.I devwalk +passes +the +.I tab +parameter to +.I gen +together with the currently-sought element of +.IR name . +If the first element is not found, +.I devwalk +returns nil; otherwise, it returns a +.B Walkqid +value in which +.B nqid +elements of the array +.B qid +are set to the qids (see +.IR intro (5)) +of each valid element of +.IR name . +If all +.I nname +elements were successfully traversed, then +.B nqid +will have the value +.IR nname , +and +.B clone +will refer to the result of the walk, +which is either +.I nc +if given, or +the new channel allocated by +.IR devwalk . +Otherwise, at least one element succeeded and +.B nqid +is less than +.I nname +and +.B clone +is nil. +On an error or incomplete walk, +the error string is set to the error that stopped the walk (eg, +.B Enonexist +or +.BR Enotdir ). +.PP +.I Devstat +fills the array of bytes +.I db +with data in the format produced by +.IR stat (5) +that describes the file +referenced by channel +.IR c , +which must have a corresponding entry +returned by +.IR gen +(ie, an entry with matching +.BR Qid.path ). +If +.I c +is a communications channel connecting a Styx server to a current mount point, +the +.B DMMOUNT +bit is set in the resulting +.BR Dir.mode , +and +.B QTMOUNT +is set in +.BR Dir.qid.type . +As in +.IR stat (5), +the length of the data written to +.I db +varies; if more than +.I n +bytes are needed, +.I devstat +raises the +.IR error (10.2) +.BR Ebadarg . +Otherwise, it returns the number of bytes in +.I db +actually used. +.PP +If an entry with the desired qid is not found in the table, but +.I c +corresponds to a directory +(ie, +.B QTDIR +is set in +.IR c\f5->qid.type\fP ), +it is taken to be a +.I stat +of a notional directory containing the files listed in +.IR tab . +.I Dirstat +then builds the corresponding Dir structure: +its +.B Dir.name +is taken from +.IR c\f5->path->elem\fP ; +the length is +.BI DIRLEN*nelem(tab) ; +and +.B Dir.perm +is 0555 (read-execute for all). +.PP +.I Devdirread +calls +.I gen +to obtain successive +.B Dir +structures representing entries in the open directory +.IR c . +These are converted to standard format (see +.I convD2M +in +.IR styx (10.2)) +and placed in the buffer +.IR b . +It returns the number of bytes in the result. +At most +.I n +bytes will be returned, in multiples of +.BR DIRLEN . +Because the kernel maintains the current offset in +.IR c , +successive calls to +.I devdirread +return successive directory components. +.PP +.I Devopen +is called to check and complete a request to open channel +.I c +for I/O according to +.IR omode +(the open mode of +.IR sys-open (2)). +It calls +.I gen +to obtain successive directory entries +which it searches +for a Qid matching that of +.IR c , +and ensures that the current user has permission to open +.I c +with the given mode, +.IR omode , +and that the mode itself is valid +(see +.I openmode +below). +Permission is checked against the permission in the +matching entry. +If no matching Qid is found, it is assumed +that the notional parent directory of the files represented in +.I tab +is to be opened. +Such a directory is deemed to have mode +0555, allowing access by any user. +A directory can only be opened for reading +.RB ( OREAD ). +.I Devopen +returns the channel +.I c +on success. +Last, it sets the bit +.B COPEN +in +.B Chan.flag +to mark +.I c +as open. +This convention can always be relied upon by the driver's +.I close +function to tell if an open succeeded. +On the otherhand, +if the open request was unsuccessful, +.I devopen +raises an appropriate +.IR error (10.2) +and does not return. +.PP +.I Devbread +returns a +.B Block +(see +.IR allocb (10.2)) +containing up to +.I n +bytes read, +using +.BI "devtab[" c "->type]->read" , +from +.I c +starting at the given +.IR offset . +The read pointer in the returned +.B Block +points to the start of the data; +the write pointer points to the next available byte. +.PP +.I Devbwrite +writes the data in +.B Block +.I bp +to the file +.I c +at the given +.IR offset , +using the write function +.BI "devtab[" c "->type]->write" . +It then frees the block list +.I bp +before +returning the number of bytes written. +.PP +Most built-in devices do not allow +.IR create , +.IR remove +or +.I wstat +on their files. +.IR Devcreate , +.I devremove +and +.I devwstat +are stubs that raise an +.IR error (10.2), +.BR Eperm . +They can be named directly in a device driver's device +switch (the +.B Dev +structure in +.BR /os/port/portdat.h : +see +.IR dev (10.2)). +.PP +.IR Devreset , +.I devinit +and +.I devshutdown +are also stubs; +they do nothing. +A device driver puts them in its +.B Dev +structure when it need take no action on device reset, initialisation, or shut down. +.PP +.I Openmode +is used by a driver that does not use +.IR devopen , +to check the open mode it receives in its open +routine. +.I Openmode +returns mode +.IR o , +the mode parameter to +.IR sys-open (2) +or +.IR sys-create , +shorn of +.BR OTRUNC +and similar options, +and reduced to one of +.BR OREAD , +.BR OWRITE +or +.BR ORDWR . +In particular, +.B OEXEC +becomes +.B OREAD +within the kernel. +.I Openmode +raises an +.IR error (10.2) +.B Ebadarg +instead of returning, if +.I o +is an invalid mode (eg, reserved bits set). +.SH SOURCE +.B /emu/port/dev.c +.br +.B /os/port/dev.c +.SH SEE ALSO +.IR allocb (10.2), +.IR eve (10.2), +.IR qio (10.2) |
