1.\" 2.\" SPDX-License-Identifier: BSD-2-Clause 3.\" 4.\" Copyright (c) 1999 Chris Costello 5.\" All rights reserved. 6.\" 7.\" Redistribution and use in source and binary forms, with or without 8.\" modification, are permitted provided that the following conditions 9.\" are met: 10.\" 1. Redistributions of source code must retain the above copyright 11.\" notice, this list of conditions and the following disclaimer. 12.\" 2. Redistributions in binary form must reproduce the above copyright 13.\" notice, this list of conditions and the following disclaimer in the 14.\" documentation and/or other materials provided with the distribution. 15.\" 16.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26.\" SUCH DAMAGE. 27.\" 28.Dd January 19, 2025 29.Dt MAKE_DEV 9 30.Os 31.Sh NAME 32.Nm make_dev , 33.Nm make_dev_cred , 34.Nm make_dev_credf , 35.Nm make_dev_p , 36.Nm make_dev_s , 37.Nm make_dev_alias , 38.Nm make_dev_alias_p , 39.Nm destroy_dev , 40.Nm destroy_dev_sched , 41.Nm destroy_dev_sched_cb , 42.Nm destroy_dev_drain , 43.Nm dev_depends 44.Nd create and destroy character devices including devfs registration 45.Sh SYNOPSIS 46.In sys/param.h 47.In sys/conf.h 48.Ft void 49.Fn make_dev_args_init "struct make_dev_args *args" 50.Ft int 51.Fn make_dev_s "struct make_dev_args *args" "struct cdev **cdev" "const char *fmt" ... 52.Ft int 53.Fn make_dev_alias_p "int flags" "struct cdev **cdev" "struct cdev *pdev" "const char *fmt" ... 54.Ft void 55.Fn destroy_dev "struct cdev *dev" 56.Ft void 57.Fn destroy_dev_sched "struct cdev *dev" 58.Ft void 59.Fn destroy_dev_sched_cb "struct cdev *dev" "void (*cb)(void *)" "void *arg" 60.Ft void 61.Fn destroy_dev_drain "struct cdevsw *csw" 62.Ft void 63.Fn dev_depends "struct cdev *pdev" "struct cdev *cdev" 64.Pp 65LEGACY INTERFACES 66.Ft struct cdev * 67.Fn make_dev "struct cdevsw *cdevsw" "int unit" "uid_t uid" "gid_t gid" "int perms" "const char *fmt" ... 68.Ft struct cdev * 69.Fn make_dev_cred "struct cdevsw *cdevsw" "int unit" "struct ucred *cr" "uid_t uid" "gid_t gid" "int perms" "const char *fmt" ... 70.Ft struct cdev * 71.Fn make_dev_credf "int flags" "struct cdevsw *cdevsw" "int unit" "struct ucred *cr" "uid_t uid" "gid_t gid" "int perms" "const char *fmt" ... 72.Ft int 73.Fn make_dev_p "int flags" "struct cdev **cdev" "struct cdevsw *devsw" "struct ucred *cr" "uid_t uid" "gid_t gid" "int mode" "const char *fmt" ... 74.Ft struct cdev * 75.Fn make_dev_alias "struct cdev *pdev" "const char *fmt" ... 76.Sh DESCRIPTION 77The 78.Fn make_dev_s 79function creates a 80.Fa cdev 81structure for a new device, which is returned into the 82.Fa cdev 83argument. 84It also notifies 85.Xr devfs 4 86of the presence of the new device, that causes corresponding nodes 87to be created. 88Besides this, a 89.Xr devctl 4 90notification is sent. 91The function takes the structure 92.Va struct make_dev_args args , 93which specifies the parameters for the device creation: 94.Pp 95.Bd -literal -offset indent -compact 96struct make_dev_args { 97 size_t mda_size; 98 int mda_flags; 99 struct cdevsw *mda_devsw; 100 struct ucred *mda_cr; 101 uid_t mda_uid; 102 gid_t mda_gid; 103 int mda_mode; 104 int mda_unit; 105 void *mda_si_drv1; 106 void *mda_si_drv2; 107}; 108.Ed 109.Pp 110Before use and filling with the desired values, the structure must be 111initialized by the 112.Fn make_dev_args_init 113function, which ensures that future kernel interface expansion does 114not affect driver source code or binary interface. 115.Pp 116The created device will be owned by 117.Va args.mda_uid , 118with the group ownership as 119.Va args.mda_gid . 120The name is the expansion of 121.Va fmt 122and following arguments as 123.Xr printf 9 124would print it. 125The name determines its path under 126.Pa /dev 127or other 128.Xr devfs 4 129mount point and may contain slash 130.Ql / 131characters to denote subdirectories. 132The permissions of the file specified in 133.Va args.mda_mode 134are defined in 135.In sys/stat.h : 136.Pp 137.Bd -literal -offset indent -compact 138#define S_IRWXU 0000700 /* RWX mask for owner */ 139#define S_IRUSR 0000400 /* R for owner */ 140#define S_IWUSR 0000200 /* W for owner */ 141#define S_IXUSR 0000100 /* X for owner */ 142 143#define S_IRWXG 0000070 /* RWX mask for group */ 144#define S_IRGRP 0000040 /* R for group */ 145#define S_IWGRP 0000020 /* W for group */ 146#define S_IXGRP 0000010 /* X for group */ 147 148#define S_IRWXO 0000007 /* RWX mask for other */ 149#define S_IROTH 0000004 /* R for other */ 150#define S_IWOTH 0000002 /* W for other */ 151#define S_IXOTH 0000001 /* X for other */ 152 153#define S_ISUID 0004000 /* set user id on execution */ 154#define S_ISGID 0002000 /* set group id on execution */ 155#define S_ISVTX 0001000 /* sticky bit */ 156#ifndef _POSIX_SOURCE 157#define S_ISTXT 0001000 158#endif 159.Ed 160.Pp 161The 162.Va args.mda_cr 163argument specifies credentials that will be stored in the 164.Fa si_cred 165member of the initialized 166.Fa struct cdev . 167.Pp 168The 169.Va args.mda_flags 170argument alters the operation of 171.Fn make_dev_s . 172The following values are currently accepted: 173.Pp 174.Bl -tag -width "MAKEDEV_CHECKNAME" -compact -offset indent 175.It Dv MAKEDEV_REF 176reference the created device 177.It Dv MAKEDEV_NOWAIT 178do not sleep, the call may fail 179.It Dv MAKEDEV_WAITOK 180allow the function to sleep to satisfy malloc 181.It Dv MAKEDEV_ETERNAL 182created device will be never destroyed 183.It Dv MAKEDEV_CHECKNAME 184return an error if the device name is invalid or already exists 185.El 186.Pp 187Only 188.Dv MAKEDEV_NOWAIT , 189.Dv MAKEDEV_WAITOK 190and 191.Dv MAKEDEV_CHECKNAME 192values are accepted for the 193.Fn make_dev_alias_p 194function. 195.Pp 196The 197.Dv MAKEDEV_WAITOK 198flag is assumed if none of 199.Dv MAKEDEV_WAITOK , 200.Dv MAKEDEV_NOWAIT 201is specified. 202.Pp 203The 204.Xr dev_clone 9 205event handler shall specify the 206.Dv MAKEDEV_REF 207flag when creating a device in response to lookup, to avoid a race where 208the created device is immediately destroyed after 209.Fn devfs_lookup 210drops its reference to 211.Fa cdev . 212.Pp 213The 214.Dv MAKEDEV_ETERNAL 215flag allows the kernel to not acquire some locks when translating system 216calls into the cdevsw methods calls. 217It is responsibility of the driver author to make sure that 218.Fn destroy_dev 219is never called on the returned cdev. 220For the convenience, use the 221.Dv MAKEDEV_ETERNAL_KLD 222flag for the code that can be compiled into kernel or loaded 223(and unloaded) as loadable module. 224.Pp 225A panic will occur if the 226.Dv MAKEDEV_CHECKNAME 227flag is not specified 228and the device name is invalid or already exists. 229.Pp 230The 231.Fn make_dev_p 232use of the form: 233.Bd -literal -offset indent 234struct cdev *dev; 235int res; 236res = make_dev_p(flags, &dev, cdevsw, cred, uid, gid, perms, name); 237.Ed 238.Pp 239is equivalent to the code: 240.Bd -literal -offset indent 241struct cdev *dev; 242struct make_dev_args args; 243int res; 244 245make_dev_args_init(&args); 246args.mda_flags = flags; 247args.mda_devsw = cdevsw; 248args.mda_cr = cred; 249args.mda_uid = uid; 250args.mda_gid = gid; 251args.mda_mode = perms; 252res = make_dev_s(&args, &dev, name); 253.Ed 254.Pp 255Similarly, the 256.Fn make_dev_credf 257function call is equivalent to: 258.Bd -literal -offset indent 259(void) make_dev_s(&args, &dev, name); 260.Ed 261.Pp 262In other words, 263.Fn make_dev_credf 264does not allow the caller to obtain the return value, and in 265kernels compiled with the 266.Va INVARIANTS 267options, the function asserts that the device creation succeeded. 268.Pp 269The 270.Fn make_dev_cred 271function is equivalent to the call: 272.Bd -literal -offset indent 273make_dev_credf(0, cdevsw, unit, cr, uid, gid, perms, fmt, ...); 274.Ed 275.Pp 276The 277.Fn make_dev 278function call is the same as: 279.Bd -literal -offset indent 280make_dev_credf(0, cdevsw, unit, NULL, uid, gid, perms, fmt, ...); 281.Ed 282.Pp 283The 284.Fn make_dev_alias_p 285function takes the returned 286.Ft cdev 287from 288.Fn make_dev 289and makes another (aliased) name for this device. 290It is an error to call 291.Fn make_dev_alias_p 292prior to calling 293.Fn make_dev . 294.Pp 295The 296.Fn make_dev_alias 297function is similar to 298.Fn make_dev_alias_p 299but it returns the resulting aliasing 300.Ft *cdev 301and may not return an error. 302.Pp 303The 304.Fa cdev 305returned by 306.Fn make_dev_s 307and 308.Fn make_dev_alias_p 309has two fields, 310.Fa si_drv1 311and 312.Fa si_drv2 , 313that are available to store state. 314Both fields are of type 315.Ft void * , 316and can be initialized simultaneously with the 317.Va cdev 318allocation by filling 319.Va args.mda_si_drv1 320and 321.Va args.mda_si_drv2 322members of the 323.Fn make_dev_s 324argument structure, or filled after the 325.Va cdev 326is allocated, if using legacy interfaces. 327In the latter case, the driver should handle the race of 328accessing uninitialized 329.Va si_drv1 330and 331.Va si_drv2 332itself. 333These are designed to replace the 334.Fa unit 335argument to 336.Fn make_dev , 337which can be obtained with 338.Fn dev2unit . 339.Pp 340The 341.Fn destroy_dev 342function takes the returned 343.Fa cdev 344from 345.Fn make_dev 346and destroys the registration for that device. 347The notification is sent to 348.Xr devctl 4 349about the destruction event. 350Do not call 351.Fn destroy_dev 352on devices that were created with 353.Fn make_dev_alias . 354.Pp 355The 356.Fn dev_depends 357function establishes a parent-child relationship between two devices. 358The net effect is that a 359.Fn destroy_dev 360of the parent device will also result in the destruction of the 361child device(s), 362if any exist. 363A device may simultaneously be a parent and a child, 364so it is possible to build a complete hierarchy. 365.Pp 366The 367.Fn destroy_dev_sched_cb 368function schedules execution of the 369.Fn destroy_dev 370for the specified 371.Fa cdev 372in the safe context. 373After 374.Fn destroy_dev 375is finished, and if the supplied 376.Fa cb 377is not 378.Dv NULL , 379the callback 380.Fa cb 381is called, with argument 382.Fa arg . 383The 384.Fn destroy_dev_sched 385function is the same as: 386.Bd -literal -offset indent 387destroy_dev_sched_cb(cdev, NULL, NULL); 388.Ed 389.Pp 390The 391.Fn d_close 392driver method cannot call 393.Fn destroy_dev 394directly. 395Doing so causes deadlock when 396.Fn destroy_dev 397waits for all threads to leave the driver methods. 398Also, because 399.Fn destroy_dev 400sleeps, no non-sleepable locks may be held over the call. 401The 402.Fn destroy_dev_sched 403family of functions overcome these issues. 404.Pp 405The device driver may call the 406.Fn destroy_dev_drain 407function to wait until all devices that have supplied 408.Fa csw 409as cdevsw, are destroyed. 410This is useful when driver knows that 411.Fn destroy_dev_sched 412is called for all instantiated devices, but need to postpone module 413unload until 414.Fn destroy_dev 415is actually finished for all of them. 416.Sh RETURN VALUES 417If successful, 418.Fn make_dev_s 419and 420.Fn make_dev_p 421will return 0, otherwise they will return an error. 422If successful, 423.Fn make_dev_credf 424will return a valid 425.Fa cdev 426pointer, otherwise it will return 427.Dv NULL . 428.Sh ERRORS 429The 430.Fn make_dev_s , 431.Fn make_dev_p 432and 433.Fn make_dev_alias_p 434calls will fail and the device will be not registered if: 435.Bl -tag -width Er 436.It Bq Er ENOMEM 437The 438.Dv MAKEDEV_NOWAIT 439flag was specified and a memory allocation request could not be satisfied. 440.It Bq Er ENAMETOOLONG 441The 442.Dv MAKEDEV_CHECKNAME 443flag was specified and the provided device name is longer than 444.Dv SPECNAMELEN . 445.It Bq Er EINVAL 446The 447.Dv MAKEDEV_CHECKNAME 448flag was specified and the provided device name is empty, contains a 449.Qq \&. 450or 451.Qq .. 452path component or ends with 453.Ql / . 454.It Bq Er EINVAL 455The 456.Dv MAKEDEV_CHECKNAME 457flag was specified and the provided device name contains invalid characters. 458.It Bq Er EEXIST 459The 460.Dv MAKEDEV_CHECKNAME 461flag was specified and the provided device name already exists. 462.El 463.Sh SEE ALSO 464.Xr devctl 4 , 465.Xr devfs 4 , 466.Xr dev_clone 9 467.Sh HISTORY 468The 469.Fn make_dev 470and 471.Fn destroy_dev 472functions first appeared in 473.Fx 4.0 . 474The function 475.Fn make_dev_alias 476first appeared in 477.Fx 4.1 . 478The function 479.Fn dev_depends 480first appeared in 481.Fx 5.0 . 482The functions 483.Fn make_dev_credf , 484.Fn destroy_dev_sched , 485.Fn destroy_dev_sched_cb 486first appeared in 487.Fx 7.0 . 488The function 489.Fn make_dev_p 490first appeared in 491.Fx 8.2 . 492The function 493.Fn make_dev_s 494first appeared in 495.Fx 11.0 . 496