From owner-freebsd-drivers@FreeBSD.ORG Thu Nov 3 04:38:28 2005 Return-Path: X-Original-To: freebsd-drivers@freebsd.org Delivered-To: freebsd-drivers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 4B53116A41F for ; Thu, 3 Nov 2005 04:38:28 +0000 (GMT) (envelope-from imp@bsdimp.com) Received: from harmony.bsdimp.com (vc4-2-0-87.dsl.netrack.net [199.45.160.85]) by mx1.FreeBSD.org (Postfix) with ESMTP id E0DF543D48 for ; Thu, 3 Nov 2005 04:38:27 +0000 (GMT) (envelope-from imp@bsdimp.com) Received: from localhost (localhost.village.org [127.0.0.1] (may be forged)) by harmony.bsdimp.com (8.13.3/8.13.3) with ESMTP id jA34a9Gh000798; Wed, 2 Nov 2005 21:36:14 -0700 (MST) (envelope-from imp@bsdimp.com) Date: Wed, 02 Nov 2005 21:36:24 -0700 (MST) Message-Id: <20051102.213624.50069863.imp@bsdimp.com> To: mayong@mail.com From: "M. Warner Losh" In-Reply-To: <20051103025038.CAF618401E@ws1-5.us4.outblaze.com> References: <20051103025038.CAF618401E@ws1-5.us4.outblaze.com> X-Mailer: Mew version 3.3 on Emacs 21.3 / Mule 5.0 (SAKAKI) Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-2.0 (harmony.bsdimp.com [127.0.0.1]); Wed, 02 Nov 2005 21:36:14 -0700 (MST) Cc: freebsd-drivers@freebsd.org Subject: Re: Interface of the driver X-BeenThere: freebsd-drivers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Writing device drivers for FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Nov 2005 04:38:28 -0000 In message: <20051103025038.CAF618401E@ws1-5.us4.outblaze.com> "Yong Ma" writes: : My driver for the cryptographic accelerator is almost finished, the : next job will be the development of user interfaces. I've got some : problems now: Is the ioctl() function the only way in which the user : implications interact with the driver(mine is a KLD module)? Yes and no. It is the typical way that most drivers choose to interact with userland. In this model, you have to add a device entry (see make_dev(9)) wher you give it a 'cdevsw' structure. This is the stylized way of doing function potiners for entry points (virtual functions in C++ use a similar mechanism) to the driver. You create a device, the user opens it and then issues requests. In your case ioctl (although I suspect read and write too). : If so, : how can I pass some arguments(such as my private key or the file : name that will be encrypted)? There are a number of macros which help you to pass arguments. The ioctl function itself takes a 'function' and a 'arguement'. Since the 'function' also encodes the size and direction of the ioctl, it can copy the arguments into the kenrel for you and copy them out when you are done. : Can I call some function(with : arguments) defined in the driver in my user implications, and how? Most drivers that define an ioctl interface have a fooio.h header. fooio.h will include and then device their command numbers. For example, mtio.h defines mag tape ioctls: /* mag tape io control commands */ #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ #define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ /* these two do not appear to be used anywhere */ #define MTIOCIEOT _IO('m', 3) /* ignore EOT error */ The first one 'writes' a magtape operation to the kernel. This is contained in a struct mtop. The struct mtop is defined in mtio.h, but I've omitted it here. The driver gets the MTIOCTOP operations, does some casting and then extracts data from the passed in structure. The kernel code looks something like: static int saioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) { int err; ... err = 0; switch (cmd) { ... case MTIOCTOP: { struct mtop *mt = (struct mtop *) arg; err = sa_process_mt(mt); break; } default: err = ENOTTY; break; } ... return (err); } The sa_process_mt routine would be something the driver wrote to interpret the struct mtop from this call. Similarly for other ioctls. _IOW() is for defining ioctls that write data into the kernel only. Most 'set' ioctls are IOW. _IOR are used to extract data from the kernel. Most 'get' ioctls are IOR. _IO ioctls are ioctls that pass no data to the kernel and do some predefined thing (like set the ignore eof flag above). _IOWR are used to pass data both ways, into and out of the kernel. These are used for more complicated 'get' routines or to communicate data back out of the kernel. In userland, the user would just include the fooio.h file and use it like they would for any other ioctl: struct foo_state { ... }; #define FOOIOCGETSTATE _IOR('f', 1, struct foo_state); ... struct foo_state state; int foo; fd = open("/dev/foo0", O_RDWR); if (fd == -1) err(1, "open"); if (ioctl(fd, FOOIOCGETSTATE, &state) == -1) err(1, "IOOIOCFETSTATE"); /* Do something with the state */ close(fd); ... hope this helps.. Warner