From owner-freebsd-hackers Wed Jan 29 19:53:33 1997 Return-Path: Received: (from root@localhost) by freefall.freebsd.org (8.8.5/8.8.5) id TAA16689 for hackers-outgoing; Wed, 29 Jan 1997 19:53:33 -0800 (PST) Received: from genesis.atrad.adelaide.edu.au (genesis.atrad.adelaide.edu.au [129.127.96.120]) by freefall.freebsd.org (8.8.5/8.8.5) with ESMTP id TAA16684 for ; Wed, 29 Jan 1997 19:53:30 -0800 (PST) Received: (from msmith@localhost) by genesis.atrad.adelaide.edu.au (8.8.2/8.7.3) id OAA26563; Thu, 30 Jan 1997 14:22:45 +1030 (CST) From: Michael Smith Message-Id: <199701300352.OAA26563@genesis.atrad.adelaide.edu.au> Subject: Re: Cases (was: Constructive Criticism) In-Reply-To: <199701300301.WAA09208@spoon.beta.com> from "Brian J. McGovern" at "Jan 29, 97 10:01:40 pm" To: mcgovern@spoon.beta.com (Brian J. McGovern) Date: Thu, 30 Jan 1997 14:22:44 +1030 (CST) Cc: msmith@atrad.adelaide.edu.au, hackers@freebsd.org X-Mailer: ELM [version 2.4ME+ PL28 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk Brian J. McGovern stands accused of saying: > > > >This is called the "learning curve". There are two ways to climb it, for > >climb it you must if you want to do anything. > > > >1) Spend lots of time trying, asking questions, exercising your intelligence > > and patience. > >2) Give lots of money to someone else to have them force you through 1). > > I disagree with your two cases. As with any development decision, if > I can't justify the cost of undertaking the certain project, I won't > even begin it. Do you read Dilbert? If it weren't for your other comments, I would have to say that you were trained management. You need to lift your eyes a little and look at the longer-term benefits of a given exercise. > In the case of #1, its a time/learning curve that is > out of reach. By the time I figure it out for release x.y.z, its > usually changed. You're joking, right? The driver integration model has changed _once_ in something like ten years, and that change is simple, straightforward, and if you asked could be explained in less than a screenfull of words. > Ok, so one bad example ;p But, still, I've noted a good chunk of the > technical docs in the handbook always seems to be a release out of > date. Again, perhaps its something that can be undertaken. Writing documentation is lots of work. Tina and her ilk are a rare resource. > >If you can't work out how device drivers are integrated, I seriously > >doubt that you're up to writing one in the first place. 8( > > > > Ah, again, a circle effect. You'll never get good till you've chewed on a > handful of them. Correct. > And you'll never start on your first till you think you > can do it. *This* is your failing point, and it is annoyingly common. Given "you can never know until you try", your attitude means that you will _never_learn_ because without an ironclad guarantee of success, you'll never make the effort. An attitude like that is a guarantee of failure. > A lack of documentation makes it infinately more difficult. I would assert that the mailing lists are a form of interactive documentation that transcends anything that can be statically committed to any media. > But, like my original > message said, if I _am_ able to learn something useful, and return an equal > amount, or more time on development than what you took to teach me, its a > win all around. Your offerings would be gratefully accepted, believe you me 8) > Unfortunately, my time to tinker with such things is limited. I've > banged out some test code in the past (simple device reads, writes, > etc), but don't have a weekend to figure out how to stick it in the > kernel. And until I know I have a weekend to make a concerted > effort, I won't bother anyone with the newbie question. Why ask the > question if the answer would be useless? How can you make an assessment like that when you claim ignorance? Perhaps integrating your driver is a 5-minute task? Will you let your timidity hold you back? > When the time comes, I'll ask. However, I'd also like to keep the > number of questions I have to ask to a bare minimum. I'd rather have > it be "I'm doing XYZPDQ, and it blows up in such and such a way. Can > any one see any obvious problem", than "What do I do now?". I think "I have some device driver routines, how do I glue them together so that the kernel can use them" is a pretty straightforward question. I could (and would happily) answer that in a fashion that you should be able to do something with directly. > For me to grow beyond copying an example in the book, I really need > to understand _why_ I'm doing what i'm doing. Why not ask them then? The authors of the code you're fretting about (or at the very least people that understand it) are all around, and most are easily approachable. > Reading someone else's chunk of code doesn't tell you WHY they > implemented something a certain way... Good commenting would, but if > all the code in the world had sufficient commenting, we wouldn't be > having this discussion :) Reading the code in its larger context will often make obvious why something was implemented in a particular fashion. Often "expediency" is the only succinct answer 8) > Tomorrow, whilest I'm at work, I will write some code for a pseudo-device > driver I wish to call foo. I will write routines for fooinit, fooread, > and foowrite. According to the documentation I've read, I should be able to > leave the open and close routines set to (I guess NULL ?) nothing. fooinit > will also exist, but will just contain a printf to announce the presence of > the pseudo-driver. The driver will be a character driver, with major number > of 20. Minor number will represent buffer numbers, each buffer will be 1K > in length. Writes to a buffer will set the string. Reads will return it (if > the full length is specified). Optionally, I'll use the offset attributes > to allow multiple reads and writes. Lastly, all of these routines will > be in a file called foodev.c. Ok, sounds like a plan. > Now, based on my reading, and what I've seen in some of the drivers > I _have_ looked at, I believe that I'll have to set a cdevsw structure up, > and it looks like a struct isa_driver. I also see probe() and attach() > routines that I have not seen documentation on before in the books I have > read. I see devfs support thrown in... Looks kinky. Probably will need help > there eventually... Ok. > Anyhow, want to lecture me on what some of these things are, whats required, > whats optional, and how my stuff will fit in the cosmic scheme of things? Sure; I'll keep it cc'd to -hackers so that others can snipe at my ignorance, and if you save all of these messages, you should have an excellent reference on which to base your documentation. 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. I'll use your 'foo' driver as an example. ==== Driver initialisation is seperated into two parts, known as 'probe' and 'attach'. The purpose of the 'probe' routine is to ascertain whether the hardware is present, and optionally determine its configuration. 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 : 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. 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. 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. 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 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); Where CDEV_MAJOR is the major device number assigned to the driver (normally #defined somewhere obvious). 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 }; Note that some of the placeholders are "no*" and some are "null*" - I think that this is laziness on someone's part 8( 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 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. You can call this several times to create multiple nodes for a single instance of the driver. ==== That should get you probing and attached; keep us in touch! > -Brian -- ]] Mike Smith, Software Engineer msmith@gsoft.com.au [[ ]] Genesis Software genesis@gsoft.com.au [[ ]] High-speed data acquisition and (GSM mobile) 0411-222-496 [[ ]] realtime instrument control. (ph) +61-8-8267-3493 [[ ]] Unix hardware collector. "Where are your PEZ?" The Tick [[