Source Code
We will now go over the source code of our driver. A network driver
stores packet information in the net_device data
structure. This data structure is defined in <linux/netdevice.h>.
Basically, the net_device structure has fields and a set of callback
functions. These fields and callback functions must be initialized by the
driver. The file drivers/net/Space.c
is responsible for detect and initialize network devices.
As explained in section 5
, we use the character count framing method for our driver.
I designed the header of the packet to be 4 bytes long which
contains the size of the packet. Let's say the value in the header is 100,
then the data frame's size is 100.
.
The problem with this design is that if a byte in the header flips during
transmission, the driver will be out of synchronization at the
destination and we will have to restart the system. Let's say
the header of a packet contains the length of 100 at the sender's end,
when it arrives at the destination, a byte in the header flips,
the header now contains 110 instead of 100 at the receiver's end. Clearly,
this puts the driver out of sync. So what do we do about this problem? Nothing.
You could change the driver to use starting and ending character at each
frame, but you will have to do some research on this.
Makefile:
z85230.h:
This file contains register descriptions of the Zilog ESCC.
z85230.c
This file contains I/O ports. These ports are used to
read, write to the hardware. Under Linux, I/O ports are defined in
<asm/io.h>. The size of the Zilog ESCC registers is 8 bits
wide, so we use inb() and outb() to read and write
to registers respectively. I have defined these functions to access
to theZilog ESCC:
void scc_outp(int port,int value);
int scc_inp(int port);
Read or write value
to registers.
void scc_putch(char ch);
Write a character to Channel
A tx fifo.
void scc_puts(char *str,int len);
Write a string to Channel A tx fifo.
int scc_getch(void);
Read a character from Channel rx fifo if
there's one there.
Returns the character read or -1 if fifo empty
.
void scc_setup ();
Get the z85230 into a vaguely sensible state
.
All values pinched from Sealevel diagnostics.
void scc_reset ();
Reset the z85230.
void iodelay();
The Zilog controller needs to be delay
by 5ms between each register access.
fifo.h
This file contains prototypes for fifo.c .
fifo.c
int init_module(void);
This is the entry point to the driver. This function calls
check_region() to verify if the range of ports is already
locked by other devices. The register_netdev() function is
responsible for registering the net_device structure with
the kernel.
void cleanup_module(void);
This function is the driver exit. It calls unregister_netdev()
to remove the net_device structure from the kernel. A compliant
network driver always calls register_netdev() and unregister_netdev().
int fifo_open (struct net_device *dev);
When you use the command ifconfig fifo0 up, this callback
function will be called by the driver. This function is responsible
to register the interrupt handler and requesting the I/O ports with
the kernel. The request_irq() is an important function. It
gets your interrupt handler called when the Zilog ESCC receives
an interrupt acknowledgement from the CPU. The request_irq()
needs the following arguments:
unsigned int irq
Linux IRQ number. Under x86 architecture,
the Linux IRQ number is the same as the hardware number that you set
with the jumper on Sealevel card.
void (*handler)(int, void *, struct pt_regs *)
Pointer to the interrupt handler
function.
unsigned long flags
The flags can be SA_INTERRUPT for
fast interrupt handler, SA_SHIRQ for share interrupt.
const char *device
Name of the interrupt
that is used in /proc/interrupt
void*dev_id
A parameter to pass to the
interrupt handler.
int fifo_stop (struct net_device *dev)
This function disable the Zilog ESCC and free the IRQ and ports.
int fifo_tx (struct sk_buff *skb, struct net_device *dev)
This function transmits packets to the RS232 interface. The
hard_start_xmit method of the net_device structure points
to fifo_tx, which is responsible for putting the data
on the wire. The fifo_tx() function calls fifo_transmit()
.
void fifo_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
This is our interrupt handler. It is triggered whenever
a byte arrived in the FIFO. I set the ESCC to interrupt every
time it receives a byte.