From owner-freebsd-hackers Thu Jan 30 00:48:53 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.5/8.8.5) id AAA28792 for hackers-outgoing; Thu, 30 Jan 1997 00:48:53 -0800 (PST) Received: from alpo.whistle.com (alpo.whistle.com [207.76.204.38]) by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id AAA28785 for ; Thu, 30 Jan 1997 00:48:48 -0800 (PST) Received: from current1.whistle.com (current1.whistle.com [207.76.205.22]) by alpo.whistle.com (8.8.4/8.8.4) with SMTP id AAA06603; Thu, 30 Jan 1997 00:44:53 -0800 (PST) Date: Thu, 30 Jan 1997 00:43:08 -0800 (PST) From: Julian Elischer To: "Brian J. McGovern" cc: msmith@atrad.adelaide.edu.au, hackers@freebsd.org Subject: Re: The continuting email... In-Reply-To: <199701300505.AAA09649@spoon.beta.com> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk On Thu, 30 Jan 1997, Brian J. McGovern wrote: > >I'll restrict myself to ISA drivers, as these are where I'm most familiar. > >PCI drivers are generally similar, but have an easier time in some > >regards. PCI drivers register themselves differently, and the PCI code recognises the harware and calls the 'attach' routine directly.. the probe() routine is redunant (yay!) > > >I'll use your 'foo' driver as an example. > > ==== > > >Probe/attach for ISA device drivers is triggered by the presence of a > >non-static isa_driver structure in the driver; at least the first three > >fields should be initialised, with the probe and attach routines and the > >name of the driver : > > Ok. I know the what. Any particular reason it has to be non-static? I assume > to cause it to blow up if there is another driver with the same name, but, > am I correct? It has to be non static because the presence of the device in teh kernel configuration file will cause a reference to this structure to be made in a generated .c file which will be linked into the kernel. look in a kernel build directory (e.g. /sys/compile/GENERIC) for the file ioconf.c . This file is generated from the kernel config file. > > Secondly, what are the fields after the first 3? nope, that's all. In other BSD systems there are sometimes more > > Also, I did a grep for "isa_driver" in /usr/include via a find (ie - > grep "isa_driver" `find .` to no avail. Which header should I include? in /sys/i386/isa/isa_device.h > > >struct isa_driver foodriver = { fooprobe, fooattach, "foo"}; > > >The 'fooprobe' function is called during startup to determine whether > >the device is present or not. It should return zero if the probe > >for the hardware failed, or the size of the I/O space occupied by > >the device if the probe succeeded. > > Please define "size of the I/O space". To me, this can mean many > things, probably all of which are wrong. Is it the number of ports a > device uses? Amount of memory (shared or otherwise)? And how about > our simulated pseudo device, which won't control hardware, but might > have a few K in buffers? The number of IO ports. you may fill in the size of the shared memory buffer in the isa_device structure (and other fields) as well > > >static int > >fooprobe(struct isa_device *dev) > > >It is legitimate to alter the contents of the fields in the isa_device > >structure, if new values are determined by probing for the hardware. > >Note that the id_irq field is a bitmask, not a numeric value. The > >probe routine should not emit any text unless it comes up against > >something particularly alarming. > > Ok. id_irq is a bitmask. I'll have to save my other questions once I can > find struct isa_device. I am currently assuming that this contains the > info in the kernel config file when called. Same for a pseudo-device? > > > > >The probe routine is called once per instance of the driver in the > >configuration file. > > > >Attach is called, again once per instance of the driver in the config, > >when the device has been successfully probed and does not conflict. > Does the driver make the call as to the conflict? Or does the system look > at the struct isa_device, and if a conflict occurs, not call the probe > and attach routines? The kernel makes the call after the probe has checked the values it was given and changed anything.. there is also (I seem to remember) a check BEFORE that as well > > > > >static int > >fooattach(struct isa_device *dev) > > > >The attach routine should build any local data structures required for > >management of the device. It is traditional for the attach routine to > >emit a line like : > > > >foo0: Snarklewacker 200, rotating Floib, no BoBoBoBoB. > > > >The startup code will have already emitted a line like : > > > >foo0 at 0x10-20 irq 1 iomem 0x12345 on isa > > > Ok. This smells like the init routines I'm used to seeing. > > > >Once internal state for the driver has been established, you add an entry > >to the device switch for the driver. In the case of a character device, > >the following fragment is normally used : > > > > dev = makedev(CDEV_MAJOR,0); > > cdevsw_add(&dev,&foo_cdevsw,NULL); > > > > Ok. Looks clear enough. I'm assuming we're still in attach here... Well, no..well, maybe.. this must be called exactly ONCE for each driver. It is possible that the attach code is called more than that so the code needs to have "have I been here before" protection.. In many drivers there is no hardware so no attach function os called. for an example look at mem.c This driver uses a facility in the kernel called SYSINIT. the SYSINIT facility allows an arbitrary function to specify where it is to be called in the boot sequence. Most drivers have a SYSINIT entry in addition to the attach/probe stuff. and pseudo-device driver MUST have one.. The SYSINIT entry usually specifies an 'init' routine that is run ONCE and ONLY ONCE (unless you have two SYSINIT entries). This is the IDEAL place to put the cdevs_add() calls as it will ensure that it happens once, before it's needed. Note also that in some ways the 'init' code is exactly what would need to be called to link in the driver had it been an LKM. when all drivers use SYSINIT and all cdevsw/bdevsw entries are dynamic and all interrupts are hooked in dynamically, then in effect you will be able to load device drivers as LKMs with no extra work. DEVFS gives you a view into this dynamic world. > I'm > also assuming that block devices would call bdevsw_add (wrong name i think, > but I think I get the idea). no, it IS bdevsw_add. notice that the bdevsw and cdevsw entries in your driver are THE ACTUAL ENTRIES. In FreeBSD the cdevsw and bdevsw tables are an array of POINTERS, and not an array of actual structs. The cdevsw_add() can be asked to CHOOSE a major number for you if you don't have one in mind. The number used is STORED IN THE cdevsw/bdevsw table entry, so examine it afterwards to discover what you got. They also have crosspointers, so given a cdev you can quickly find the related bdev and visa versa. (and also the driver 'name' for use in error messages etc. (e.g. 'foo') > How about STREAMS typesi BSD doesn't have streams, but if they did they would be initialised through the same SYSINIT method (see /sys/kernel.h) (SI_SUB_DRIVERS) as we don't have them I have no idea how you'd access them :) > or tty type devices that tty devices are just normal devices.. pty devices are pseudo devices and thus have a SYSINIT entry. > are linked off through a line protocol? Once I'm done with driver foo, > I'd like to start work on an ISA multi-modem card thats being prepped > by Cisco for inclusion in to their routers (the modem modules, not the ISA > cards). I'll need to run SLIP and PPP across the link. the _documentation I > have_ says I'll have to make it a little more special than a "normal" character > device... why? > > >Where CDEV_MAJOR is the major device number assigned to the driver > >(normally #defined somewhere obvious). Well Majors are assigned in /sys/i386/conf/majors (or something) but that file isn't actually used..it's just for reference. > > > >A typical cdevsw initialisation might look like : > > > >static d_open_t fooopen; > >static d_close_t fooclose; > >static d_read_t fooread; > >static d_write_t foowrite; > >static d_ioctl_t fooioctl; > >static d_select_t fooselect; > > > >#define CDEV_MAJOR 20 > >static struct cdevsw foo_cdevsw = > >{ > > fooopen, fooclose, fooread, foowrite, > > fooioctl, nullstop, nullreset, nodevtotty, > > fooselect, nommap, NULL, driver_name, > > NULL, -1 > >}; > > > > Ok. Some of it makes sense. Is there a blank generic one that gives the > appropriate order? For instance, I see nullstop and nullreset. There should > also be a poll routine in there some where? Is it a NULL? a no? a -1? Poll is sysV there is no poll in BSD.. the similar entry is the 'select' entry. > >Note that some of the placeholders are "no*" and some are "null*" - I > >think that this is laziness on someone's part 8( > Again, see the note above. Docs on what they "should be" could help fix this :) agreed.. it MIGHT be in conf.h > > > > >To create a devfs device node : > > > > sc->devfs_token = devfs_add_devsw(&foo_cdevsw, unit, > > DEV_CHR, UID_ROOT, GID_WHEEL, > > 0660, "foo%d", unit); > > > >This returns a token which is saved (here) in the devfs_token field in > >the device's softc structure (the per-device state structure). The reason for keeping the token is in case you want to removethe device. you do so by supplying the token you were given to the devfs_??? function (it's in the chapter 9 man page I believe) > >The > >cdevsw structure defines the driver's entrypoints, unit is the unit > >number associated with the device node (you can encode major/minor > >data here if you wish), DEV_CHR indicates a character device node, the > >UID_ROOT, GID_WHEEL and 0660 entries set the ownership/permissions on > >the new device node, and the remaining arguments are printf-style, > >with a format string and parameters for the format string which yield > >the name of the device node. > > > Ok. Is creating a devfs node mandatory? I know people would like to move to > it, but when/is it required? What makes the decision if it is optional? Well If I can get the bugs shaken out we should move to it asap :) > > >You can call this several times to create multiple nodes for a single > >instance of the driver. > > Ok. I assume this means that it'll generate the same major numbers with > appropriate minor numbers? no, YOU supply a differnt minor number and name each time.. this is effectively making entries in /dev for your driver. you can also make links for devices that want different names. how you interpret teh minor number is up to the driver so only the driver can decide how to allocate them.. > > I appreciate the help to date. Again, my goal is not to argue, but to > assist. Can't assist without knowledge, can't gain knowledge without > documentation (I despise cultural learning. Too much pure data > gets damaged in the retelling...) > julian (let me know more about this device and PPP I may have some info for you on that too) >