DEVATTACH(10.2) DEVATTACH(10.2)
NAME
devattach, devclone, devdir, devgen, devwalk, devdirread,
devstat, devopen, devbread, devbwrite, devcreate, devremove,
devwstat, devreset, devinit, openmode - common device driver
support
SYNOPSIS
typedef int
Devgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp);
Chan* devattach(int tc, char *spec);
Chan* devclone(Chan *c, Chan *nc);
void devdir(Chan *c, Qid qid, char *n, long length,
char *user, long perm, Dir *dp);
int devgen(Chan *c, Dirtab *tab, int ntab,
int i, Dir *dp);
int devwalk(Chan *c, char *name, Dirtab *tab,
int ntab, Devgen *gen);
void devstat(Chan *c, char *db, Dirtab *tab,
int ntab, Devgen *gen);
long devdirread(Chan *c, char *d, long n, Dirtab *tab,
int ntab, Devgen *gen);
Chan* devopen(Chan *c, int omode,Dirtab *tab,
int ntab, Devgen *gen);
Block* devbread(Chan *c, long n, ulong offset)
long devbwrite(Chan *c, Block *bp, ulong offset);
void devcreate(Chan*, char*, int, ulong);
void devremove(Chan*);
void devwstat(Chan*, char*);
void devreset(void);
void devinit(void);
int openmode(ulong mode);
DESCRIPTION
Device drivers call these functions to carry out essential
Page 1 Plan 9 (printed 12/15/25)
DEVATTACH(10.2) DEVATTACH(10.2)
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 Chan structures
correctly.
A device has an associated type, represented as a Unicode
character (`rune') that identifies the device inside and
outside the kernel. It appears as the value of the type
field in the Dir resulting from a sys-stat(2) of any file
provided by the device. A device is named outside the ker-
nel using a path name starting with # followed by the device
character (eg, c in #c for the console). Any subsequent
characters before the next '/' or end of string is the
`device specifier', interpreted solely by the device itself.
Devattach returns a new channel representing the root of the
file tree corresponding to device type tc, with device spec-
ifier spec. It is normally called by a driver's attach func-
tion (see dev(10.2)). The qid for the new channel is
(Qid){CHDIR,0}, suitable for a root directory for many
devices, but a device driver is free to change it (provided
the CHDIR bit remains in the QID.path).
Devclone makes a copy of c in nc, returning the value of nc.
If nc is null, a new channel is returned with a copy of c .
An attempt to clone an open channel causes a panic(10.2).
The `Dir' structure is shown below:
typedef
struct Dir
{
char name[NAMELEN];
char uid[NAMELEN];
char gid[NAMELEN];
Qid qid;
ulong mode;
int atime;
int mtime;
ulong length;
ushort type;
ushort dev;
} Dir;
This Dir structure corresponds directly to the Limbo Dir adt
described in sys-stat(2).
Given a channel and assorted other information, devdir ini-
tialises a Dir structure at dp. Devdir supplies the
Page 2 Plan 9 (printed 12/15/25)
DEVATTACH(10.2) DEVATTACH(10.2)
following data itself:
atime last access time (set to current time)
mtime last modification time (set to kernel creation
date)
gid group name (set to eve(10.2))
length length in bytes (set to zero, which is normal
for most devices)
Devdir sets the flag bit CHMOUNT in dp->mode if the channel
c corresponds to a file descriptor on which Styx is served
(see export in sys-dial(2) and mount in sys-bind(2)).
A simple name space can be represented in a driver by an
array of Dirtab structures. The array is typically static
when the names and permissions are static, but can be dynam-
ically allocated and initialised if required. The structure
of Dirtab is shown below:
typedef
struct Dirtab
{
char name[NAMELEN];
Qid qid;
long length;
long perm;
} Dirtab;
The names `.' and `..' never appear in a Dirtab table.
Drivers that support a directory hierarchy must walk up the
hierarchy towards the root when their walk function receives
`..' as a file name component. The name `.' is never seen
by a driver.
The devdirread, devopen, devstat, and devwalk functions all
take a gen function argument, of type Devgen, which they
invoke to retrieve the items in a Chan that represents a
directory. Gen takes a channel c (a directory), an array of
Dirtab structures tab of length ntab, and a table index i.
The functions calling gen expect it to place the i'th entry
in the directory into *dp. It should return 1 if the call
was successful, -1 if i is beyond the index of the last
directory entry, or 0 if there is no entry at i, but there
are entries beyond it. Custom implementations of gen often
ignore devtab, and instead return their own dynamically gen-
erated set of directory entries from some other source.
The function devgen is compatible with Devgen; it returns
the i'th entry in devtab, and can be used to provide a sim-
ple, static set of directory entries.
Devwalk walks channel c to the file in tab with the given
Page 3 Plan 9 (printed 12/15/25)
DEVATTACH(10.2) DEVATTACH(10.2)
name. Devwalk returns true if the name is found, and false
otherwise (it also sets the process's error string to
Enonexist). The qid and path fields of c are updated
accordingly: c->qid is set to the Qid in the Dirtab entry
for the file; name is added to c->path.
Devstat fills the array of bytes db with data in the format
produced by stat(5) that describes the file referenced by
channel c, which must have a corresponding entry returned by
gen (ie, an entry with matching Qid.path). If c is a commu-
nications channel connecting a Styx server to a current
mount point, the CHMOUNT bit is set in the resulting
Dir.mode.
If an entry with the desired qid is not found in the table,
but c corresponds to a directory (ie, CHDIR is set in c-
>qid.path), it is taken to be a stat of a notional directory
containing the files listed in tab. Dirstat then builds the
corresponding Dir structure: its Dir.name is taken from c-
>path->elem; the length is DIRLEN*nelem(tab); and Dir.perm
is 0555 (read-execute for all).
Devdirread calls gen to obtain successive Dir structures
representing entries in the open directory c. These are con-
verted to standard format (see convD2M in styx(10.2)) and
placed in the buffer b. It returns the number of bytes in
the result. At most n bytes will be returned, in multiples
of DIRLEN. Because the kernel maintains the current offset
in c, successive calls to devdirread return successive
directory components.
Devopen is called to check and complete a request to open
channel c for I/O according to omode (the open mode of sys-
open(2)). It calls gen to obtain successive directory
entries which it searches for a Qid matching that of c, and
ensures that the current user has permission to open c with
the given mode, omode, and that the mode itself is valid
(see 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 tab is to be opened. Such a direc-
tory is deemed to have mode 0555, allowing access by any
user. A directory can only be opened for reading (OREAD).
Devopen returns the channel c on success. Last, it sets the
bit COPEN in Chan.flag to mark c as open. This convention
can always be relied upon by the driver's close function to
tell if an open succeeded. On the otherhand, if the open
request was unsuccessful, devopen raises an appropriate
error(10.2) and does not return.
Devbread returns a Block (see allocb(10.2)) containing up to
n bytes read, using devtab[c->type]->read, from c starting
Page 4 Plan 9 (printed 12/15/25)
DEVATTACH(10.2) DEVATTACH(10.2)
at the given offset. The read pointer in the returned Block
points to the start of the data; the write pointer points to
the next available byte.
Devbwrite writes the data in Block bp to the file c at the
given offset, using the write funcion
devtab[c->type]->write. It then frees the block list bp
before returning the number of bytes written.
Most built-in devices do not allow create, remove or wstat
on their files. Devcreate, devremove and devwstat are stubs
that raise an error(10.2), Eperm. They can be named
directly in a device driver's device switch (the Dev struc-
ture in /os/port/portdat.h).
Devreset and devinit are also stubs; they do nothing. A
device driver puts them in its Dev structure when it need
take no action on either reset or device initialisation.
Openmode is used by a driver that does not use devopen, to
check the open mode it receives in its open routine.
Openmode returns mode o, the mode parameter to sys-open(2)
or sys-create, shorn of OTRUNC and similar options, and
reduced to one of OREAD, OWRITE or ORDWR. In particular,
OEXEC becomes OREAD within the kernel. Openmode raises an
error(10.2) Ebadarg instead of returning, if o is an invalid
mode (eg, reserved bits set).
SOURCE
/emu/dev.c
/os/port/dev.c
SEE ALSO
allocb(10.2), eve(10.2), qio(10.2)
Page 5 Plan 9 (printed 12/15/25)