Difference between revisions of "Writing network drivers for KolibriOS"

From KolibriOS wiki
Jump to navigation Jump to search
(Created page with 'So, you want to write a new network driver for KolibriOS ? Or you are just curious about how they work? Well, since a driver for an ethernet, pci card, such as the rtl8139, actua...')
 
(Fixes for <asm> tags - replaced with <syntaxhighlight>)
 
(7 intermediate revisions by one other user not shown)
Line 1: Line 1:
So, you want to write a new network driver for KolibriOS ?
+
= Intro =
 +
 
 +
So, you want to write a new network driver for KolibriOS ?<br />
 
Or you are just curious about how they work?
 
Or you are just curious about how they work?
Well, since a driver for an ethernet, pci card, such as the rtl8139, actually isnt that hard to understand, I advice you to read the code of a driver and try to understand it.</ br>
+
Well, since a driver for an ethernet, pci card, such as the rtl8139, actually isnt that hard to understand,<br />
 
+
I advice you to read the code of a driver and try to understand it.<br />
Here are some facts, summed op in no-particular order
 
 
 
;Drivers are designed to handle more then one devices at once.
 
;All device specific data is stored in a structure called the 'device structure'.
 
;Network drivers are loaded by a program (NetCfg).
 
;A program can communicate directly with the driver, using system function 68/17
 
  
 +
Here are some facts, summed op in no-particular order:
 +
* Drivers are designed to handle more then one devices at once.
 +
* All device specific data is stored in a structure called the 'device structure'.
 +
* Network drivers are loaded by a program (NetCfg).
 +
* A program can communicate directly with the driver, using system function 68/17
  
For this, it uses the IOCTL structure wich looks like this:
+
= IOCTL input =
<asm>
 
struc IOCTL {
 
  .handle      dd ?
 
  .io_code    dd ?
 
  .input       dd ?
 
  .inp_size    dd ?
 
  .output      dd ?
 
  .out_size    dd ? 
 
}
 
</asm>
 
for more info about this, please read [[Writing_drivers_for_KolibriOS]]
 
  
Here is a list of opcodes:
+
Here is a list of opcodes the network drivers should accept trhough the IOCTL structure:
 
;0 - Getversion
 
;0 - Getversion
 
standard for all drivers, not only network drivers
 
standard for all drivers, not only network drivers
Line 30: Line 20:
 
;1 - Hook  
 
;1 - Hook  
 
Attach driver to a device<br>
 
Attach driver to a device<br>
 +
 +
 +
= the HOOK procedure =
 +
 +
This is a part of the service proc.
 +
 +
The application calling the hook procedure should give informationa bout the device with one of these structures:
  
 
IN: (ISA)
 
IN: (ISA)
<asm>
+
<syntaxhighlight lang="asm">
 
type    db 0 ; isa
 
type    db 0 ; isa
 
io_addr  dw ?  
 
io_addr  dw ?  
 
irq_line db ?  
 
irq_line db ?  
</asm>
+
</syntaxhighlight>
  
 
IN: (PCI)
 
IN: (PCI)
<asm>
+
<syntaxhighlight lang="asm">
 
type    db 1 ; pci
 
type    db 1 ; pci
 
pci_bus  db ?  
 
pci_bus  db ?  
 
pci_dev  db ?  
 
pci_dev  db ?  
</asm>
+
</syntaxhighlight>
  
OUT:<br>
+
The driver should do the following:
eax = device number or -1 on error
 
  
 +
# check if device is already listed in the drivers list
 +
# allocate a device structure
 +
# fill in io num, irq, device type, pointers to network procedures
 +
# allocate buffers needed for the driver
 +
# probe the device
 +
# reset the device
 +
# register device to kernel using NetRegDev
  
----
+
Then it should return the driver number, or -1 on error, in eax
  
== The device stucture ==
+
= The device stucture =
  
Once the HOOK function of the driver has been called, the driver creates the NET_DEVICE structure, allocates some buffers needed for the driver, validates if a given device is supported by the driver, and calls the kernel function 'NetRegDev'.<br>
+
This structure contains all information about the device the driver has.
This function registers a network device (device, not driver!) to the kernel, it only needs one parameter: pointer to device structure (NET_DEVICE) in ebx.<br>
+
It is also used to communicate with kernel.
The function returns the device number in edi (..wich the driver then sends to the application in eax)
+
It hold the MTU, driver functions to send/reset/.. the mac address,...
  
This NET_DEVICE structure is created and filled in by the driver for every device it is hooked to.<br>
 
The driver may use this to store pointers to buffers, descriptors,.. etc<br>
 
 
The top of the structure must always look like this: (Since it is shared by the driver and the kernel)
 
The top of the structure must always look like this: (Since it is shared by the driver and the kernel)
(it is defined in netdrv.inc)
 
  
<asm>
+
<syntaxhighlight lang="asm">
 
NET_DEVICE:
 
NET_DEVICE:
 
         .type          dd ?    ; Type field (ethernet/slip/...)
 
         .type          dd ?    ; Type field (ethernet/slip/...)
Line 78: Line 78:
  
 
         .end:
 
         .end:
</asm>
+
</syntaxhighlight>
  
 
This is appended by a Type-specific structure, for ethernet this will be:
 
This is appended by a Type-specific structure, for ethernet this will be:
 
+
<syntaxhighlight lang="asm">
<asm>
 
 
         .set_mode      dd ?
 
         .set_mode      dd ?
 
         .get_mode      dd ?
 
         .get_mode      dd ?
Line 91: Line 90:
 
         .mode          dd ?
 
         .mode          dd ?
 
         .mac            dp ?     
 
         .mac            dp ?     
</asm>
+
</syntaxhighlight>
 +
 
 +
These structures are defined in netdrv.inc
 +
 
 +
The place after these two common structs is to be used by the driver, to store store information about the device.
  
Wich is then followed by the private data, the driver uses to store information about the device.
+
= receiving mechanism =
  
 
When a packet is received by the driver, the driver copies it into a buffer allocated using 'KernelAlloc'.<br>
 
When a packet is received by the driver, the driver copies it into a buffer allocated using 'KernelAlloc'.<br>
Then the driver pushes the size of the buffer and the pointer to the buffer onto the stack (both are dwords, and must be pushed in this particular order)<br>
+
It then pushes a return address on the stack, where kernel should jump to when done handling the packet.
And it calls 'EthReceiver' (or another procedure for another network device type).<br>
+
This is followed bye the pushing of the buffer size and the buffer pointer (both are dwords, and must be pushed in this particular order)<br>
 +
 
 +
Then the driver jumps to 'EthReceiver' (or another procedure for another network device type).<br>
 
This kernel function will return with the 2 dwords removed from the stack.
 
This kernel function will return with the 2 dwords removed from the stack.
 +
 +
= sending mechanism =
  
 
When the kernel needs to send a packet, it simple looks up the appropriate driver in it's driver table.<br>
 
When the kernel needs to send a packet, it simple looks up the appropriate driver in it's driver table.<br>
In the table it will find the pointer to the device structure, so the driver can directly call the transmit function listed in the structure.
+
In the table it will find the pointer to the device structure, so the kernel can directly call the transmit function listed in the structure.
  
 
The kernel will, similary to the driver, when receiving a packet, push the size of packet, and pointer to packet, onto the stack.
 
The kernel will, similary to the driver, when receiving a packet, push the size of packet, and pointer to packet, onto the stack.
 +
But not in the same order, it first pushes the dwords and then does a call. (so ptr will be at [esp+4] and size at [esp+8])
  
....More to come..
+
[[Category:Coding]]

Latest revision as of 12:42, 22 April 2012

Intro

So, you want to write a new network driver for KolibriOS ?
Or you are just curious about how they work? Well, since a driver for an ethernet, pci card, such as the rtl8139, actually isnt that hard to understand,
I advice you to read the code of a driver and try to understand it.

Here are some facts, summed op in no-particular order:

  • Drivers are designed to handle more then one devices at once.
  • All device specific data is stored in a structure called the 'device structure'.
  • Network drivers are loaded by a program (NetCfg).
  • A program can communicate directly with the driver, using system function 68/17

IOCTL input

Here is a list of opcodes the network drivers should accept trhough the IOCTL structure:

0 - Getversion

standard for all drivers, not only network drivers

1 - Hook

Attach driver to a device


the HOOK procedure

This is a part of the service proc.

The application calling the hook procedure should give informationa bout the device with one of these structures:

IN: (ISA)

type     db 0 ; isa
io_addr  dw ? 
irq_line db ?

IN: (PCI)

type     db 1 ; pci
pci_bus  db ? 
pci_dev  db ?

The driver should do the following:

  1. check if device is already listed in the drivers list
  2. allocate a device structure
  3. fill in io num, irq, device type, pointers to network procedures
  4. allocate buffers needed for the driver
  5. probe the device
  6. reset the device
  7. register device to kernel using NetRegDev

Then it should return the driver number, or -1 on error, in eax

The device stucture

This structure contains all information about the device the driver has. It is also used to communicate with kernel. It hold the MTU, driver functions to send/reset/.. the mac address,...

The top of the structure must always look like this: (Since it is shared by the driver and the kernel)

NET_DEVICE:
        .type           dd ?    ; Type field (ethernet/slip/...)
        .mtu            dd ?    ; Maximal Transmission Unit (in bytes)
        .name           dd ?    ; Ptr to 0 terminated string 

        .unload         dd ?    ; Ptrs to driver functions
        .reset          dd ?    ;
        .transmit       dd ?    ;

        .bytes_tx       dq ?    ; Statistics, updated by the driver
        .bytes_rx       dq ?    ;
        .packets_tx     dd ?    ;
        .packets_rx     dd ?    ;

        .end:

This is appended by a Type-specific structure, for ethernet this will be:

        .set_mode       dd ?
        .get_mode       dd ?

        .set_MAC        dd ?
        .get_MAC        dd ?

        .mode           dd ?
        .mac            dp ?

These structures are defined in netdrv.inc

The place after these two common structs is to be used by the driver, to store store information about the device.

receiving mechanism

When a packet is received by the driver, the driver copies it into a buffer allocated using 'KernelAlloc'.
It then pushes a return address on the stack, where kernel should jump to when done handling the packet. This is followed bye the pushing of the buffer size and the buffer pointer (both are dwords, and must be pushed in this particular order)

Then the driver jumps to 'EthReceiver' (or another procedure for another network device type).
This kernel function will return with the 2 dwords removed from the stack.

sending mechanism

When the kernel needs to send a packet, it simple looks up the appropriate driver in it's driver table.
In the table it will find the pointer to the device structure, so the kernel can directly call the transmit function listed in the structure.

The kernel will, similary to the driver, when receiving a packet, push the size of packet, and pointer to packet, onto the stack. But not in the same order, it first pushes the dwords and then does a call. (so ptr will be at [esp+4] and size at [esp+8])