From mboxrd@z Thu Jan 1 00:00:00 1970 Message-ID: <820bc1260604140836p4ba0baby9b9ef3d081d2fb51@mail.gmail.com> Date: Fri, 14 Apr 2006 10:36:02 -0500 From: "Eric Smith" To: "Fans of the OS Plan 9 from Bell Labs" <9fans@cse.psu.edu> Subject: Re: [9fans] Writing device drivers In-Reply-To: <820bc1260604140834v2a773ev90ff46b4e6b2427f@mail.gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_9820_1490587.1145028962339" References: <8a5bd8ccbc2e53557663e2a9020fb26c@coraid.com> <820bc1260604140834v2a773ev90ff46b4e6b2427f@mail.gmail.com> Topicbox-Message-UUID: 369d5b2e-ead1-11e9-9d60-3106f5b1d025 ------=_Part_9820_1490587.1145028962339 Content-Type: multipart/alternative; boundary="----=_Part_9821_20689973.1145028962339" ------=_Part_9821_20689973.1145028962339 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Thank you SO much -- this was just the sort of thing I needed. Pointing ou= t the ethernet interface, /sys/src/9/pc/devether.c, and small, easily understood, sample drivers like etherec2t.c and ether2000.c is just what I needed. And you guessed it -- I have spent zero time in kernel mode. But I'm anxious to try :) Use of pointers in C has always been a sticky point for me although it shouldn't be. Because I have a background with low-level languages like assembly I thoroughly understand doing things in memory, registers, etc, bu= t for some reason, understanding the _why_ of using pointers in C has eluded me -- like what is to be gained by accessing functions via a table of pointers. But that is just what I hope to learn by working on this project= . Truly, though, my C sucks. I do hope to improve it through this ... I do hope to succeed. But to give you an idea of how horrible my C is I've attached a piece of code I wrote for a (hobby) microcontroller project. This is for an 8-bit Atmel RISC. I know this bears little relation to a device driver living in kernel space -- and no one would write non-blocking code like this as a device driver. But it's probably the best example I have (attached). Please pardon the heavy comments -- that is the one thing I have learned about C: I can go back and look at old, say, Pascal code of mine, and read it. But 6 months after writing a little piece of C it's tough for me to read it and figure out what in the world I was thinking. So I go overboard with the comments. I realize I'm submitting my sorry C code to a group of really strong C programmers -- if nothing else it should provde some amusement :) Thank you for your help!!!! Regards, Eric On 4/14/06, Brantley Coile wrote: > > > Interesting question. I just spend a few moments looking around and > thinking about suggestions for helping you up the learning curve. The > more I thought about it, the more I wondered where you were already on > that curve. Recommendations depend on that sort of thing. > > Suggestions break into three parts: C skills, general device driver > skills, and Plan 9 specific knowledge. The C skills fall into three > categories: the syntax and semantics of the language, common > techniques and paradigm, and skill in software design, constructing > solution from small functions and that sort of thing. The syntax and > semantics problem can most easily be fixed by a quick re-read of Brian > and Dennis' book, the famaous K&R. Most likely you've read that > before, but I re-read it every few years or so. Amazing that a > language so small can take a life time to fully learn. (And I'm not > talking about C99.) > > Common techniques and paradigms, since you want to write a Plan 9 > device driver, is best learned by reading Plan 9 code. Lots of nice > small things in /sys/src/cmd are great for this. As with natural > languages, the best way to learn to write is to read. I owe > everything to this principle. > > The skills in design are much harder to obtain. You may already be > strong in this department since it's not unique to C. The two > attributes of cohesion and coupling are the key ideas here. Good code > in Oberon, Java, C, PL/I or COBOL are all the same. > > Brian and Rob's book, `The Practice of Programming' is the best > I know of for this kind of stuff. > > I assume from your comment that you time spend writing stuff in kernel > mode is limited. Sorry if this isn't the case. Things you should > learn include, the restricted context of kernel mode, the issues > regarding locking in the multiprocessor Plan 9 kernel, how interrupt > handlers get registered and called, limitations on what you can do in > the interrupt handler, how processes sleep and wakeup, and more. > Interfacing to the under part of Plan 9 is easy. It's just a 9P > server with function calls instead of messages. Simple device drivers > in like /sys/src/9/pc/devrtc.c show how the device driver interfaces > with the system. > > But you want to write a driver for the WPN311, so you'll need to study > the ethernet interface in /sys/src/9/pc/devether.c, and look at an > ethernet sample driver like etherec2t.c and ether2000.c . These are > pretty small and show how to glue into the devether.c code. > Devether.c factors out all the common work of ethernet drivers and > uses a table of pointers to functions to get the specific work done by > a given driver. > > Hope that helps some. I've never written a wireless driver so I don't > know about any specific gotchas with that. Good luck on it. It's a > great feeling to get a driver working. > > Brantley > > > ------=_Part_9821_20689973.1145028962339 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Thank you SO much -- this was just the s= ort of thing I needed.  Pointing out the ethernet interface, /sys/src/= 9/pc/devether.c, and small, easily understood, sample drivers like etherec2= t.c and=20 ether2000.c is just what I needed.

And you guessed it -- I have spent z= ero time in kernel mode.  But I'm anxious to try :)

Use of poin= ters in C has always been a sticky point for me although it shouldn't be.&n= bsp; Because I have a background with low-level languages like assembly I t= horoughly understand doing things in memory, registers, etc, but for some r= eason, understanding the _why_ of using pointers in C has eluded me -- like= what is to be gained by accessing functions via a table of pointers. = But that is just what I hope to learn by working on this project.

Truly, though, my C sucks.  I do hope to improve it through th= is ... I do hope to succeed.

But to give you an idea of how horrible= my C is I've attached a piece of code I wrote for a (hobby) microcontrolle= r project.  This is for an 8-bit Atmel RISC.  I know this bears l= ittle relation to a device driver living in kernel space -- and no one woul= d write non-blocking code like this as a device driver.  But it's prob= ably the best example I have (attached).

Please pardon the heavy comments -- that is the one thing I have le= arned about C:  I can go back and look at old, say, Pascal code of min= e, and read it.  But 6 months after writing a little piece of C it's t= ough for me to read it and figure out what in the world I was thinking.&nbs= p; So I go overboard with the comments.

I realize I'm submitting my sorry C code to a group of really stron= g C programmers -- if nothing else it should provde some amusement :)
Thank you for your help!!!!

Regards,
Eric


On 4/14/06, Brantley Coile <brantley@coraid.com> wrote:
Interesting question.  I just spend a few moments looking aro= und and
thinking about suggestions for helping you up the learning curve= .  The
more I thought about it, the more I wondered where you = were already on
that curve.  Recommendations depend on that sort of thing.
Suggestions break into three parts: C skills, general device driver
ski= lls, and Plan 9 specific knowledge.  The C skills fall into three=
categories: the syntax and semantics of the language, common
techniques and paradigm, and skill in software design, constructing
= solution from small functions and that sort of thing.  The syntax= and
semantics problem can most easily be fixed by a quick re-read of Br= ian
and Dennis' book, the famaous K&R.  Most likely you've read t= hat
before, but I re-read it every few years or so.  Amazing t= hat a
language so small can take a life time to fully learn.  = (And I'm not
talking about C99.)

Common techniques and paradigms, since you want to write a Plan 9device driver, is best learned by reading Plan 9 code.  Lots of= nice
small things in /sys/src/cmd are great for this.  As wit= h natural
languages, the best way to learn to write is to read. &nb= sp;I owe
everything to this principle.

The skills in design are much hard= er to obtain.  You may already be
strong in this department si= nce it's not unique to C. The two
attributes of cohesion and coupling ar= e the key ideas here.  Good code
in Oberon, Java, C, PL/I or COBOL are all the same.

Brian and Ro= b's book, `The Practice of Programming' is the best
I know of for this k= ind of stuff.

I assume from your comment that you time spend writing= stuff in kernel
mode is limited.  Sorry if this isn't the case.  Th= ings you should
learn include, the restricted context of kernel mode, th= e issues
regarding locking in the multiprocessor Plan 9 kernel, how inte= rrupt
handlers get registered and called, limitations on what you can do= in
the interrupt handler, how processes sleep and wakeup, and more.
Int= erfacing to the under part of Plan 9 is easy.  It's just a 9P
= server with function calls instead of messages.  Simple device dr= ivers
in like /sys/src/9/pc/devrtc.c show how the device driver interfac= es
with the system.

But you want to write a driver for the WPN311, = so you'll need to study
the ethernet interface in /sys/src/9/pc/devether= .c, and look at an
ethernet sample driver like etherec2t.c and ether2000= .c .  These are
pretty small and show how to glue into the deveth= er.c code.
Devether.c factors out all the common work of ethernet driver= s and
uses a table of pointers to functions to get the specific work don= e by
a given driver.

Hope that helps some.  I've never written = a wireless driver so I don't
know about any specific gotchas with that.&= nbsp; Good luck on it.  It's a
great feeling to get a dri= ver working.

Brantley




------=_Part_9821_20689973.1145028962339-- ------=_Part_9820_1490587.1145028962339 Content-Type: text/x-csrc; name=acq.c; charset=us-ascii Content-Transfer-Encoding: 7bit X-Attachment-Id: f_em0oess2 Content-Disposition: attachment; filename="acq.c" /* vim: set sw=8 ts=8 si : * Author : Eric Smith * Date : July 2005 * Chip type : ATMEGA8 * Clock frequency : 400 kHz (external ceramic resonator) * Program : acq.c * Number : 0x0A * Data Format Version : 0x1A * * This program acquires data from three sensors and stores in EEPROM. * Data from one of the three sensors (jumper selectable) is displayed on * PORTD's 8 LED display. EEPROM writes occur once per write interval * which can be once per second, minute, five minutes, or hour. After EEPROM * is full, or SS_WRITE_ENABLE jumper is unset, writes will cease, however, * the display will continue to update constantly. * * Data Format (ver 0x1A): * EEPROM @ 0x000 = Program Number * EEPROM @ 0x001 = Data Format Version Number * EEPROM @ 0x002 - 0x1FF = 170 3-byte records * Record Format (3 bytes): * Byte 0 = thermistor * Byte 1 = photocell * Byte 2 = magnetic ******************************************************************************/ #include #include /* GLOBALS */ // JIFFIES_CONSTANT should be set to the number of times the program // can pass through the main loop in one second. This will be the basis for // setting the write interval (1 per sec, 1 per min, 1 per 5mins, or 1 per hour) // While this processor is capable of running on a 16 MHz clock we are loping // along at 400 kHz to save power ... which is ok: there's no rush. const unsigned long int JIFFIES_CONSTANT = 850; const unsigned long int led_lit_limit = 85; // should be JIFFIES_CONSTANT/10 char flags = 0; // clear all flags // sense switch: 1=flash PC5 LED on writes, 0=quiet const int SS_LED_ENABLE = (1<<0); // sense switch: 1=allow display on PORTD, 0=quiet const int SS_DISPLAY_ENABLE = (1<<1); // sense switch: 1=write enabled, 0=write disabled const int SS_WRITE_ENABLE = (1<<2); unsigned long int loop_counter; uint8_t record_number; unsigned short int PC = 0x000; // this is the EEPROM address pointer uint8_t SAMPLE_INTERVAL; /* How often to record data: 0 = 1 per second 1 = 1 per minute 2 = 1 every 5 minutes 3 = 1 per hour */ uint8_t DISPLAY_SELECTION; /* What to display on PORTD LEDs: 0 = record number 1 = thermistor 2 = photocell 3 = magnetic */ struct { uint8_t thermistor; uint8_t photocell; uint8_t magnetic; } sensor; /* FUNCTION PROTOTYPES */ void delay_ms(unsigned short); void eeprom_write_byte(unsigned char, unsigned int); void init(void); void read_sense_switches(void); void acquire_data(void); void display_data(uint8_t); void write_data(void); /* FUNCTIONS */ void delay_ms(unsigned short ms) // delay for a minimum of // with a 1Mhz clock, the resolution is 1 ms { uint8_t i,j; while (ms) { i = 40; // 40 for 400 kHz clock, 100 for 1 MHz, etc while (i) { i--; j = 70; while (j) { j--; } } ms--; } } void eeprom_write_byte(unsigned char data_byte, unsigned int eepromAddr) // Write a byte of data to eeprom at eepromAddr { while (EECR & (1< led_lit_limit) // lit limit exceeded PORTC |= _BV(PC5); // then turn LED off } if ((flags & SS_DISPLAY_ENABLE) !=0) { // if DISPLAY is enabled // invert bits and display data on Port D LEDs // (must be inverted 'cause LEDs are active low) switch (selection) { case 0: PORTD = ~record_number; break; case 1: PORTD = ~sensor.thermistor; break; case 2: PORTD = ~sensor.photocell; break; case 3: PORTD = ~sensor.magnetic; break; } } } void write_data() // Write data in sensor structure to EEPROM at eepromAddr // Light PC5 LED if enabled through sense switches (SS_LED_ENABLE) { if ((flags & SS_LED_ENABLE) != 0) // if LED is enabled PORTC &= ~_BV(PC5); // then turn it ON! (active low) eeprom_write_byte(sensor.thermistor, PC++); eeprom_write_byte(sensor.photocell, PC++); eeprom_write_byte(sensor.magnetic, PC++); } int main(void) { init(); // initialization routine to be run once only unsigned long int loop_limit = JIFFIES_CONSTANT; // for starters uint8_t record_limit = 170; // 170 records = 2 bytes + (170 *3) // first byte is program number // second byte is record type // record type describes data structure // of 170 records of 3 bytes each while (1) { // THIS IS THE MAIN LOOP loop_counter = 0; while (loop_counter < loop_limit) { read_sense_switches(); switch (SAMPLE_INTERVAL) { case 0: // write ONCE PER SECOND loop_limit = JIFFIES_CONSTANT; break; case 1: // write ONCE PER MINUTE loop_limit = JIFFIES_CONSTANT * 60; break; case 2: // write ONCE PER FIVE MINUTES loop_limit = JIFFIES_CONSTANT * 300; break; case 3: // write ONCE PER HOUR loop_limit = JIFFIES_CONSTANT * 3600; break; } acquire_data(); display_data(DISPLAY_SELECTION); loop_counter++; } // loop_counter has exceeded loop_limit, time to write data // BUT, write EEPROM only if record limit not exceeded. // (will continue to loop and display even if EEPROM is full) if (record_number < record_limit) { if ((flags & SS_WRITE_ENABLE) !=0) { write_data(); record_number++; } } } // close of main loop -- will loop here forever, always displaying // data, and writing to EEPROM only if WRITE_ENABLE is set and // record_limit is not exceeded } ------=_Part_9820_1490587.1145028962339--