Writing network drivers for KolibriOS: Difference between revisions

From KolibriOS wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 96: Line 96:


....More to come..
....More to come..
[[Category:Coding]]

Revision as of 11:56, 23 July 2010

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.</ 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

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

IN: (ISA) <asm> type db 0 ; isa io_addr dw ? irq_line db ? </asm>

OUT:
eax = device number or -1 on error

--or--

IN: (PCI) <asm> type db 1 ; pci pci_bus db ? pci_dev db ? </asm>

OUT:
eax = device number or -1 on error

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'.
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.
The function returns the device number in edi (..wich the driver then sends to the application in eax)

This NET_DEVICE structure is created and filled in by the driver for every device it is hooked to.
The driver may use this to store pointers to buffers, descriptors,.. etc
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> 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:

</asm>

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

<asm>

       .set_mode       dd ?
       .get_mode       dd ?
       .set_MAC        dd ?
       .get_MAC        dd ?
       .mode           dd ?
       .mac            dp ?    

</asm>

Wich is then followed by the private data, the driver uses to store information about the device.

When a packet is received by the driver, the driver copies it into a buffer allocated using 'KernelAlloc'.
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)
And it calls 'EthReceiver' (or another procedure for another network device type).
This kernel function will return with the 2 dwords removed from the stack.

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 driver 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.

....More to come..