MAKE_DEV(9)

NAME
destroy_dev, destroy_only_dev, devfs_scan_callback, dev_ops_intercept, dev_ops_remove_all, dev_ops_remove_minor, dev_ops_restore, make_dev, make_dev_alias, make_dev_covering, make_only_dev, reference_dev, release_dev - device entry manipulation functions

SYNOPSIS
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/devfs.h>
void
destroy_dev(cdev_t dev);
void
destroy_only_dev(cdev_t dev);
int
devfs_scan_callback(devfs_scan_t *callback, void *arg);
struct dev_ops *
dev_ops_intercept(cdev_t dev, struct dev_ops *iops);
int
dev_ops_remove_all(struct dev_ops *ops);
void
dev_ops_restore(cdev_t dev, struct dev_ops *oops);
int
dev_ops_remove_minor(struct dev_ops *ops, int minor);
cdev_t
make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...);
int
make_dev_alias(cdev_t target, const char *fmt, ...);
cdev_t
make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...);
cdev_t
make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...);
cdev_t
reference_dev(cdev_t dev);
void
release_dev(cdev_t dev);

DESCRIPTION
The make_dev() function creates a cdev_t structure for a new device and makes the device name visible in the devfs(5) mount points. The device's name must be unique. The name is the expansion of fmt and following arguments as kprintf(9) would print it. The name determines its path under /dev. The permissions of the file specified in perms are defined in <sys/stat.h>:

    #define S_IRWXU 0000700    /* RWX mask for owner */
    #define S_IRUSR 0000400    /* R for owner */
    #define S_IWUSR 0000200    /* W for owner */
    #define S_IXUSR 0000100    /* X for owner */
    #define S_IRWXG 0000070    /* RWX mask for group */
    #define S_IRGRP 0000040    /* R for group */
    #define S_IWGRP 0000020    /* W for group */
    #define S_IXGRP 0000010    /* X for group */
    #define S_IRWXO 0000007    /* RWX mask for other */
    #define S_IROTH 0000004    /* R for other */
    #define S_IWOTH 0000002    /* W for other */
    #define S_IXOTH 0000001    /* X for other */
    #define S_ISUID 0004000    /* set user id on execution */
    #define S_ISGID 0002000    /* set group id on execution */
    #define S_ISVTX 0001000    /* sticky bit */
    #if __BSD_VISIBLE
    #define S_ISTXT 0001000
    #endif

The ops argument is a pointer to a dev_ops data structure, which is defined as follows:

    struct dev_ops {
            struct {
                    const char      *name;  /* base name, e.g. 'da' */
                    int              maj;   /* major device number */
                    u_int            flags; /* D_XXX flags */
                    void            *data;  /* custom driver data */
                    int              refs;  /* ref count */
                    int              id;
            } head;
    #define dev_ops_first_field     d_default
            d_default_t     *d_default;
            d_open_t        *d_open;
            d_close_t       *d_close;
            d_read_t        *d_read;
            d_write_t       *d_write;
            d_ioctl_t       *d_ioctl;
            d_mmap_t        *d_mmap;
            d_strategy_t    *d_strategy;
            d_dump_t        *d_dump;
            d_psize_t       *d_psize;
            d_kqfilter_t    *d_kqfilter;
            d_clone_t       *d_clone;       /* clone from base dev_ops */
            d_revoke_t      *d_revoke;
    #define dev_ops_last_field      d_revoke
    };

While one can and should initialize the name and maj fields, they are effectively ignored. Device major numbers are assigned automatically out of an internal pool of major numbers, so there is no need to specify a unique major number in the dev_ops structure.

Every member of the d_xxx_t() family is defined as:

    typedef int d_xxx_t (struct dev_xxx_args *ap);

Therefore, if one wants to implement a mydev_open() function, this is the way:

    d_open_t mydev_open;
    int
    mydev_open(struct dev_open_args *ap)
    {
    }

make_dev_covering() is equivalent to make_dev(), except that it also takes an argument bops which is set as the ops of the backing device for the newly created device. This function should be used whenever a device is created covering another raw device, as the disk subsystem does.

make_only_dev() creates a cdev_t structure and initializes it in the same way as make_dev() would, but the device will not appear in the devfs(5) namespace. This function is usually used in the clone handler of an autoclone device created by make_autoclone_dev().

destroy_dev() takes the returned cdev_t from make_dev() and destroys the registration for that device. It should not be used to destroy a cdev_t created by make_only_dev().

destroy_only_dev() takes the returned cdev_t from make_only_dev() and destroys the registration for that device. It should not be used to destroy a cdev_t created by make_dev().

make_dev_alias() creates an automatic devfs(5) link (alias) with the given name to the cdev_t specified by target. The cdev_t must have been created either by make_dev() or bt a clone handler. Aliases are alternative names for devices in the devfs(5) namespace. The lifetime of an alias is that of its associated cdev_t. Once the cdev_t is removed or destroyed, the alias is also destroyed and its name is removed from the devfs(5) namespace.

reference_dev() adds a reference to dev. Callers generally add their own references when they are going to store a device node in a variable for long periods of time, to prevent a disassociation from freeing the node.

release_dev() releases a reference on dev. The device will be terminated when the last reference has been released.

dev_ops_intercept() intercepts the device operations vector of dev with iops. The old dev_ops is returned which may be used in a subsequent dev_ops_restore() call. The function sets the SI_INTERCEPTED flag in dev.

dev_ops_restore() restores the device operations vector of dev to oops. Also it unsets the SI_INTERCEPTED flag in dev.

dev_ops_remove_all() destroys all the cdev_t with the given ops and removes the devices from the devfs(5) namespace. This function is useful when uninitializing a driver.

dev_ops_remove_minor() destroys all the cdev_t with the given ops and minor and removes the devices from the devfs(5) namespace.

devfs_scan_callback() calls the given callback function for every device registered in devfs(5). The callback function has the following form:

    devfs_scan_t mydev_scan_callback;
    void
    mydev_scan_callback(char *name, cdev_t dev, bool is_alias, void *arg)
    {
    };

The name argument is the alias' name (if is_alias is true) or the cdev's si_name field.

SEE ALSO
devfs(5), make_autoclone_dev(9)

HISTORY
The make_dev() and destroy_dev() functions first appeared in FreeBSD 4.0.

A major overhaul of these functions occurred in DragonFly 2.3 with the addition of devfs(5).