Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 01 Feb 1997 17:18:59 -0800
From:      Julian Elischer <julian@whistle.com>
To:        "Brian J. McGovern" <mcgovern@spoon.beta.com>
Cc:        hackers@freebsd.org
Subject:   Re: Device driver help needed...
Message-ID:  <32F3EB83.41C67EA6@whistle.com>
References:  <199702012336.SAA12533@spoon.beta.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Brian J. McGovern wrote:
> 
> Ok. I'm sure that now I've terribly bastardized the uio structure, but at
> least the damn thing compiles :) Let see if I can get some comment
> on my interpretation of the uio stucture:
> 
> struct uio
>   {
>     struct iovec *uio_iov;   /* Pointer to IO Vector (possible array?) */
				pointer to ARRAY OF IOVECS (POSSIBLY ONLY 1)
				(I know that's what you said but....)
>     int uio_iovcnt;          /* Number of IO vectors (?) */
					(size of array above)
>     off_t uio_offset;        /* Offset in to device */
>     int   uio_resid;         /* Length of read request (?) */
				number of bytes STILL TO BE TRANSFERED
>     enum uio_seg uio_segflg; /* I assume a segment of some kind, but I
>                                 can only find reference to UIO_SYSSPACE */
				the addresses in the iovec are to be interpretted
				as being in:
				KV space, User space, etc.etc.

>     enum uio_rw uio_rw;      /* UIO_READ or UIO_WRITE (type of operation(?)) */
				yes.. TO or FROM the addresses inn the iovec array
>     struct proc *uio_procp;  /* No idea, but I've seen it set to curproc */
				pointer of the proc structure associated
				with the operation 
				needed if using UIO_USERSPACE.

>   };
> 
> Ok, guys. Beat me up, and let me know whats incorrect.
> 
> With that in mind, I've bent my device driver to look like this:
> 
> ------ foo.c ---------------------------------------
> #define KERNEL
> #include <sys/param.h>
> #include <sys/systm.h>
> #include <sys/reboot.h>
> #include <sys/ioctl.h>
> #include <sys/tty.h>
> #include <sys/proc.h>
> #include <sys/conf.h>
> #include <sys/file.h>
> #include <sys/uio.h>
> #include <sys/kernel.h>
> #include <sys/malloc.h>
> #include <sys/syslog.h>
> #ifdef DEVFS
> #include <sys/devfsext.h>
> #endif
> #include <machine/clock.h>
> #include <i386/isa/isa.h>
> #include <i386/isa/isa_device.h>
> 
> static char message[] = "The quick brown fox jumps over a lazy dog\n";
> 
> #define CDEV_MAJOR 20

are you sure 20 is unused?
I guess it's for local use.. that's fine.

> 
> static d_read_t fooread;
> 
> static struct cdevsw foo_cdevsw =
>   {
>     nxopen, nxclose, fooread, nxwrite,
>     nxioctl, nxstop, nxreset, nxdevtotty,
>     nxselect, nxmmap, NULL, "foo", NULL, -1
>   };
> 
you are going to have trouble openning the device if it 
returns ENXIO.. (nxopen?)

> fooinit()
>   {
>   }
> 
> static int fooread(dev,myuio, flag)
>   dev_t dev;
>   struct uio *myuio;
>   int flag;
>   {
>     unsigned char *buffer_pointer;
>     int toread;
>     if ((myuio->uio_iovcnt != 1) || (MINOR(dev) != 0))
what if it's 2?

>       return ENODEV;

and anyway, wouldn't EINVAL be a better response to no user memory
buffer..

>     while(myuio->uio_resid)
exactly.. keep doing it till we have the required data.

>       {
>         buffer_pointer = (message + (myuio->uio_offset % sizeof(message)));
what's message?
is this a ring buffer?


>         toread = ((long unsigned int)(message + sizeof(message)) - (long unsigned int)buffer_pointer);
I don't follow this very well.


>         uiomove(buffer_pointer, toread, myuio);
yep.. (I haven't chaecked the  arguments but that's the basic idea
how about checking the return value of uiomove eh?

it returns an errno value you can pass straight to the user.
(return it, the syscall code will put it into errno.)


>         myuio->uio_offset + toread;

you mean += surely..

>         myuio->uio_resid = myuio->uio_resid - toread;

using -= would be more readable..

>       }
>   }
> #define CDEV_MAJOR 20
> 
> -------------------------------------------------
> 
> Now, I'm sure there are bugs in there. Hell, I didn't know what I was doing
> half the time :) But, now its time to start debugging, which means I need
> to get it in to the kernel. Someone mentioned using SYSINIT to get it working
> as a pseudo-device driver. The file above is located in
> /usr/src/sys/i386/addons/foo.c. Anyone care to give me a set of steps (and
> code changes) to get it in the kernel? Thanks.
>         -Brian

ok
cd /sys/i386/conf
cp GENERIC MYKERN
cat > /sys/i386/conf/files.MYKERN <<DONE
i386/addons/foo.c	optional foodev
DONE
cat >>MYKERN <<DONE
options	FOODEV
options DDB
DONE
config MYKERN
cd ../../compile/MYKERN
make depend
make
*edit for syntax errors*
make
{repeat} edit/make/edit/make

cp kernel /kernel.test
mknod /dev/foo c 20 0

sync
sync
reboot

Boot:  kernel.test -s
[boot messages]
# 
cat </dev/foo
*CRASH* (probable :)
* now you are in DDB  I suggest you print out the man page before 
trying this so you can use the debugger..
OR 
do you have 2 machines?
if so, you can use GDB over the serial port..
from the still running machine
amazing to use..


julian



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?32F3EB83.41C67EA6>