Template Information

Trang

Chủ đề

BSP (44) Device Drivers (43) WinCE (38) WINDOWS DRIVER (19) Linux Device Drivers (18) ARM (17) Android tools and tips (17) DRIVER FILES (16) Windows Device Driver (16) AUDIO DRIVER (12) 8051 (8) OMAP (7) PRINTER DRIVER FILES (7) C Programming (6) ASUS MOTHERBOARD (5) Interfacing (5) NETWORK ADAPTER (5) VIDEO DRIVER (5) CANON (3) Device Driver Downloads (3) MOBILE PHONE (3) Asus Driver (2) EPSON (2) Epson Printer Driver (2) HP LAPTOP DRIVER (2) LAPTOP DRIVER FILES (2) Logitech Driver (2) NETWORK ADAPTOR (2) OMAP 4430 (2) drivers download (2) ACER (1) ACER TABLET (1) ALL IN ONE DRIVER (1) Acer Aspire 5738 Drivers (1) Analog-to-Digital (1) Asus Drivers (1) Asus Motherboard Drivers (1) Chip Architecture (1) DELL (1) Dell D610 Drivers (1) Dell Drivers (1) Device Drivers Download (1) Device drivers interview questions (1) Display Driver (1) Drivers Download for Windows 7 (1) EEPROMs (1) Free Asus Motherboard Drivers (1) Free Drivers Download for Windows 7 (1) GRAPHIC DRIVER (1) HP Driver (1) Hardware (1) Intel Drivers (1) Intel P35 (1) Intel P35 chipset drivers (1) I²C (1) LAPTOP SERVICE MANUAL (1) LCD (1) Logitech Mouse Driver (1) Logitech webcam driver (1) MODEM DRIVER (1) Motherboard Drivers for Windows 7 (1) PARALLEL PORT (1) Pc Driver (1) RTOS (1) Real Time Clock (1) Sensors (1) USB CABLE DRIVER (1) WEBCAM DRIVER (1) WIRELESS ADAPTOR (1) Windows 7 Drivers (1) Windows Mobile (1) acer driver (1) acer driver downloads (1) acer laptop driver (1) chipset drivers (1) network card driver (1) network driver download (1) sdcc (1)

Bài viết ngẫu nhiên

Xem phim HD Online

Số lượt views

Hiển thị các bài đăng có nhãn Device Drivers. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Device Drivers. Hiển thị tất cả bài đăng

Microcontrollers and the GNU Public License (GPL)

Chủ Nhật, 9 tháng 10, 2011 / 09:06

Open Source software is released according to the terms of the GNU Public License, GPL. The GPL is intended to guarantee your rights to use, modify and copy the subject software. Along with the rights comes an obligation. If you modify and subsequently distribute software covered by the GPL, you are obligated to make available the modified source code. The changes become a “derivative work” which is also subject to the terms of the GPL. This allows other users to understand the software better and to make further changes if they wish.

This works well for most software but there is at least one problem. Suppose, for example, that you write a clever application that you wish to keep proprietary. If you link it with a C library covered by the GPL, your application becomes a derivative work and thus you’re required to distribute your source code.

To get around this, and therefore promote the development of Open Source libraries, the Free Software Foundation came up with the “Library GPL.” The distinction is that a program linked to a library covered by the LGPL is not considered a derivative work and so there’s no requirement to distribute the source, although you must still distribute the source to the library itself.
Subsequently, the LGPL became known as the “Lesser GPL” because it offers less freedom to the user. So while the LGPL makes it possible to develop proprietary products using Open Source software, the FSF encourages developers to place their libraries under the GPL in the interest of maximizing openness.

Here is a list of GPL software for microcontroller developers.
  • SDCC: a Freeware, retargettable, optimizing ANSI - C compiler that targets the Intel 8051, Maxim 80DS390, Zilog Z80 and the Motorola 68HC08 based MCUs (GPL)
  • GNUPIC: a collect of GNU software for PIC microcontrollers
  • WinAVR: a suite of executable, open source software development tools for the Atmel AVR series on the Windows
  • GNUARM: GNU toolchain ARM microcontrollers
Chủ Nhật, 9 tháng 10, 2011 09:06 Đọc tiếp >>

I²C

Chủ Nhật, 7 tháng 8, 2011 / 04:20

I²C (play /ˈ skwɛərd ˈs/ or /ˈ t ˈs/; Inter-Integrated Circuit; generically referred to as "two-wire interface") is a multi-master serial single-ended computer bus invented by Philips that is used to attach low-speed peripherals to a motherboard, embedded system, or cellphone or other electronics. Since the mid 1990s several competitors (e.g. Siemens AG (later Infineon Technologies AG), NEC, Texas Instruments, STMicroelectronics (formerly SGS-Thomson), Motorola (later Freescale), Intersil, etc.) brought I²C products on the market, which are fully compatible with the NXP (formerly Philips' semiconductor division) I²C-system. As of October 10, 2006, no licensing fees are required to implement the I²C protocol. However, fees are still required to obtain I²C slave addresses allocated by NXP.[1]
SMBus, defined by Intel in 1995, is a subset of I²C that defines the protocols more strictly. One purpose of SMBus is to promote robustness and interoperability. Accordingly, modern I²C systems incorporate policies and rules from SMBus, sometimes supporting both I²C and SMBus with minimal re-configuration required.

Design

A sample schematic with one master (a microcontroller), three slave nodes (an ADC, a DAC, and a microcontroller), and pull-up resistors Rp
I²C uses only two bidirectional open-drain lines, Serial Data Line (SDA) and Serial Clock (SCL), pulled up with resistors. Typical voltages used are +5 V or +3.3 V although systems with other voltages are permitted.
The I²C reference design has a 7-bit address space with 16 reserved addresses, so a maximum of 112 nodes can communicate on the same bus. Common I²C bus speeds are the 100 kbit/s standard mode and the 10 kbit/s low-speed mode, but arbitrarily low clock frequencies are also allowed. Recent revisions of I²C can host more nodes and run at faster speeds (400 kbit/s Fast mode, 1 Mbit/s Fast mode plus or Fm+, and 3.4 Mbit/s High Speed mode). These speeds are more widely used on embedded systems than on PCs. There are also other features, such as 16-bit addressing.
Note that the bit rates quoted are for the transactions between master and slave without clock stretching or other hardware overhead. Protocol overheads include a slave address and perhaps a register address within the slave device as well as per-byte ACK/NACK bits. So the actual transfer rate of user data is lower than those peak bit rates alone would imply. For example, if each interaction with a slave inefficiently allows only 1 byte of data to be transferred, the data rate will be less than half the peak bit rate.
The maximum number of nodes is limited by the address space, and also by the total bus capacitance of 400 pF, which restricts practical communication distances to a few meters.

[edit] Reference design

The reference design, as mentioned above, is a bus with a clock (SCL) and data (SDA) lines with 7-bit addressing. The bus has two roles for nodes: master and slave:
  • Master node — node that issues the clock and addresses slaves
  • Slave node — node that receives the clock line and address.
The bus is a multi-master bus which means any number of master nodes can be present. Additionally, master and slave roles may be changed between messages (after a STOP is sent).
There are four potential modes of operation for a given bus device, although most devices only use a single role and its two modes:
  • master transmit — master node is sending data to a slave
  • master receive — master node is receiving data from a slave
  • slave transmit — slave node is sending data to the master
  • slave receive — slave node is receiving data from the master
The master is initially in master transmit mode by sending a start bit followed by the 7-bit address of the slave it wishes to communicate with, which is finally followed by a single bit representing whether it wishes to write(0) to or read(1) from the slave.
If the slave exists on the bus then it will respond with an ACK bit (active low for acknowledged) for that address. The master then continues in either transmit or receive mode (according to the read/write bit it sent), and the slave continues in its complementary mode (receive or transmit, respectively).
The address and the data bytes are sent most significant bit first. The start bit is indicated by a high-to-low transition of SDA with SCL high; the stop bit is indicated by a low-to-high transition of SDA with SCL high.
If the master wishes to write to the slave then it repeatedly sends a byte with the slave sending an ACK bit. (In this situation, the master is in master transmit mode and the slave is in slave receive mode.)
If the master wishes to read from the slave then it repeatedly receives a byte from the slave, the master sending an ACK bit after every byte but the last one. (In this situation, the master is in master receive mode and the slave is in slave transmit mode.)
The master then ends transmission with a stop bit, or it may send another START bit if it wishes to retain control of the bus for another transfer (a "combined message").

[edit] Message protocols

I²C defines three basic types of messages, each of which begins with a START and ends with a STOP:
  • Single message where a master writes data to a slave;
  • Single message where a master reads data from a slave;
  • Combined messages, where a master issues at least two reads and/or writes to one or more slaves.
In a combined message, each read or write begins with a START and the slave address. After the first START, these are also called repeated START bits; repeated START bits are not preceded by STOP bits, which is how slaves know the next transfer is part of the same message.
Any given slave will only respond to particular messages, as defined by its product documentation.
Pure I²C systems support arbitrary message structures. SMBus is restricted to nine of those structures, such as read word N and write word N, involving a single slave. PMBus extends SMBus with a Group protocol, allowing multiple such SMBus transactions to be sent in one combined message. The terminating STOP indicates when those grouped actions should take effect. For example, one PMBus operation might reconfigure three power supplies (using three different I2C slave addresses), and their new configurations would take effect at the same time: when they receive that STOP.
With only a few exceptions, neither I²C nor SMBus define message semantics, such as the meaning of data bytes in messages. Message semantics are otherwise product-specific. Those exceptions include messages addressed to the I²C general call address (0x00) or to the SMBus Alert Response Address; and messages involved in the SMBus Address Resolution Protocol (ARP) for dynamic address allocation and management.
In practice, most slaves adopt request/response control models, where one or more bytes following a write command are treated as a command or address. Those bytes determine how subsequent written bytes are treated and/or how the slave responds on subsequent reads. Most SMBus operations involve single byte commands.

[edit] Messaging example: 24c32 EEPROM

One specific example is the 24c32 type EEPROM, which uses two request bytes that are called Address High and Address Low. (Accordingly, these EEPROMs aren't usable by pure SMBus hosts, which only support single byte commands or addresses.) These bytes are used to address bytes within the 32 kbit (4 kB) supported by that EEPROM; the same two byte addressing is also used by larger EEPROMs, such as 24c512 ones storing 512 kbits (64 kB). Writing and reading data to these EEPROMs uses a simple protocol: the address is written, and then data is transferred until the end of the message. (That data transfer part of the protocol also makes trouble for SMBus, since the data bytes are not preceded by a count and more than 32 bytes can be transferred at once. I2C EEPROMs smaller than 32 kbits, such as 2 kbit 24c02 ones, are often used on SMBus with inefficient single byte data transfers.)
To write to the EEPROM, a single message is used. After the START, the master sends the chip's bus address with the direction bit clear (write), then sends the two byte address of data within the EEPROM and then sends data bytes to be written starting at that address, followed by a STOP. When writing multiple bytes, all the bytes must be in the same 32 byte page. While it's busy saving those bytes to memory, the EEPROM won't respond to further I2C requests. (That's another incompatibility with SMBus: SMBus devices must always respond to their bus addresses.)
To read starting at a particular address in the EEPROM, a combined message is used. After a START, the master first writes that chip's bus address with the direction bit clear (write) and then the two bytes of EEPROM data address. It then sends a (repeated) START and the EEPROM's bus address with the direction bit set (read). The EEPROM will then respond with the data bytes beginning at the specified EEPROM data address—a combined message, first a write then a read. The master issues a STOP after the first data byte it NACKs rather than ACKs (when it's read all it wants). The EEPROM increments the address after each data byte transferred; multi-byte reads can retrieve the entire contents of the EEPROM using one combined message.

[edit] Physical layer

At the physical layer, both SCL & SDA lines are of open-drain design, thus, pull-up resistors are needed. Pulling the line to ground is considered a logical zero while letting the line float is a logical one. This is used as a channel access method. High speed systems (and some others) also add a current source pull up, at least on SCL; this supports faster rise times and higher bus capacitance.
Transitions for data bits are always performed while the clock is low; transitions while it is high are "start" and "stop" markers delimiting a bus transaction.
When idle, both lines are high. To start a transaction, SDA is pulled low while SCL remains high. Releasing SDA to float high again would be a stop marker, which would be pointless immediately after a start, so the next step is to pull SCL low.
When one node is transmitting a logical one (i.e., letting the line float to Vdd) and another transmits a logical zero then the first node can sense this because the line is not in a logical one state — it is not pulled up to Vdd. When used on SCL, this is called "clock stretching" and gives slaves a flow control mechanism. When used on SDA, this is called arbitration and ensures there is only one transmitter at a time.
While SCL is low, the transmitter (initially the master) sets SDA to the desired value and (after a small delay to let the value propagate) lets SCL float high. The master then waits for SCL to actually go high; this will be delayed by the finite rise-time of the SCL signal (the RC time constant of the pull-up resistor and the parasitic capacitance of the bus). and may be additionally delayed by a slave's clock stretching.
When SCL is high, the receiver latches the bit, and the master waits a minimum time (4 μs for standard speed I²C), then pulls it low again. This completes transmission of one bit.
After every 8 data bits in one direction, an "acknowledge" bit is transmitted in the other. The transmitter and receiver switch roles for one bit and the erstwhile receiver transmits a single 0 bit (ACK) back. If the transmitter sees a 1 bit (NACK) instead, it learns that:
  • If the master is transmitting, the slave is unable to accept the data. No such slave, command not understood, or unable to accept any more data.
  • If the slave is transmitting, the master wishes it to stop after this data byte.
After the acknowledge bit, the master may do one of three things:
  1. Prepare to transmit another byte of data: set SDA to the desired bit value and pulse SCL high..
  2. Send a "Stop": Set SDA low, let SCL go high, then let SDA go high. This releases the I²C bus.
  3. Send a "Repeated start": Set SDA high, let SCL go high, and pull SDA low again. This starts a new I²C bus transaction without releasing the bus.

[edit] Clock stretching using SCL

One of the more significant features of the I²C protocol is clock stretching. An addressed slave device may hold the clock line (SCL) low after receiving (or sending) a byte, indicating that it is not yet ready to process more data. The master that is communicating with the slave will attempt to raise the clock to transfer the next bit, but must verify that the clock line was actually raised. If the slave is clock stretching, the clock line will still be low (because the connections are open-drain). The same is true if a second, slower, master tries to drive the clock at the same time. (If there is more than one master, all but one of them will normally lose arbitration.)
Although the master may also hold the SCL line low for as long as it desires, the term "clock stretching" is normally used only when slaves do it. If the slave is a microcontroller, its I²C interface will stretch the clock after every byte, until the software decides what to transmit next.
Some masters, such as those found inside custom ASICs may not support clock stretching; often these devices will be labeled as a "two-wire interface" and not I²C.
To ensure a minimum bus throughput, SMBus places limits on how far clocks may be stretched. Hosts and slaves adhering to those limits can't block access to the bus for more than a short time, which is not a guarantee made by pure I²C systems.

[edit] Arbitration using SDA

Every master monitors the bus for start and stop bits, and does not start a message while another master is keeping the bus busy. However, two masters may start transmission at about the same time; in this case, arbitration occurs. Slave transmit mode can also be arbitrated, when a master addresses multiple slaves, but this is less common. In contrast to protocols (such as Ethernet) that use random back-off delays before issuing a retry, I²C has a deterministic arbitration policy. Each transmitter checks the level of the data line (SDA) and compares them with the levels it expects; if they don't match, that transmitter has lost arbitration, and drops out of this protocol interaction.
For example, if one transmitter sets SDA to 1 (not driving a signal) and a second transmitter sets it to 0 (pull to ground), the result is that the line is low. The first transmitter then observes that the level of the line is different than expected, and concludes that another node is transmitting. The first node to notice such a difference is the one that loses arbitration: it stops driving SDA. If it's a master, it also stops driving SCL and waits for a STOP; then it may try to reissue its entire message. In the meantime, the other node has not noticed any difference between the expected and actual levels on SDA, and therefore continues transmission. It can do so without problems because so far the signal has been exactly as it expected; no other transmitter has disturbed its message.
If the two masters are sending a message to two different slaves, the one sending the lower slave address always "wins" arbitration in the address stage. Since the two masters may send messages to the same slave address—and addresses sometimes refer to multiple slaves—arbitration must continue into the data stages.
Arbitration occurs very rarely, but is necessary for proper multi-master support. As with clock-stretching, not all devices support arbitration. Those that do generally label themselves as supporting "multi-master" communication.
In the extremely rare case that two masters simulaneously send the identical messages. then both will regard the communication as successful, but the slave will only see one message. Slaves that can be accessed by multiple masters must have commands that are idempotent for this reason.
SMBus uses arbitration in two additional contexts, both of which are used to pass information asynchronously from slaves to the (single) host. The first context is that hosts must support the "host notify protocol". That is a restricted multi-master mode in which slaves write messages to the reserved "SMBus Host" address (0x08), passing their address and two bytes of data. When two slaves try to notify the host at the same time, one of them will lose arbitration and need to retry. The other context is that pure slave devices which issue the SMBALERT# interrupt need to arbitrate when they reply to requests issued to the reserved "SMBus Alert Response Address" (0x0c), which is a kind of broadcast address. When they successfully reply with their own address, winning an arbitration in "slave transmit" mode, they stop raising that interrupt. In both cases, arbitration applies when the slave address is transmitted.

[edit] Timing diagram

Data transfer sequence
Data transfer is initiated with the START bit (S) when SDA is pulled low while SCL stays high. Then, SDA sets the transferred bit while SCL is low (blue) and the data is sampled (received) when SCL rises (green). When the transfer is complete, a STOP bit (P) is sent by releasing the data line to allow it to be pulled up while SCL is constantly high.

[edit] Example of bit-banging the I2C Master protocol

Below is an example of Bit-banging the I2C protocol as an I2C master. The example is written in pseudo C. It illustrates all of the i2c features described before (Clock stretching, Arbitration, start/stop bit, ack/nack)
/* Hardware-Specific Support Functions That MUST Be Customized */
#define I2CSPEED 100
void I2CDELAY() {volatile int v; int i; for(i=0;i<I2CSPEED/2;i++) v;}
bool READSCL(void) {return 1;} /* Set SCL as input and return current level of line, 0 or 1 */
bool READSDA(void) {return 1;} /* Set SDA as input and return current level of line, 0 or 1 */
void CLRSCL(void) {} /* Actively drive SCL signal low */
void CLRSDA(void) {} /* Actively drive SDA signal low */
void ARBITRATION_LOST(void) {}

/* Global Data */
bool started = false;

void i2c_start_cond(void)
{
/* if started, do a restart cond */
if (started) {
/* set SDA to 1 */
READSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
}
if (READSDA() == 0)
ARBITRATION_LOST();
/* SCL is high, set SDA from 1 to 0 */
CLRSDA();
I2CDELAY();
CLRSCL();
started = true;
}

void i2c_stop_cond(void)
{
/* set SDA to 0 */
CLRSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, set SDA from 0 to 1 */
if (READSDA() == 0)
ARBITRATION_LOST();
I2CDELAY();
started = false;
}

/* Write a bit to I2C bus */
void i2c_write_bit(bool bit)
{
if (bit)
READSDA();
else
CLRSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, now data is valid */
/* If SDA is high, check that nobody else is driving SDA */
if (bit && READSDA() == 0)
ARBITRATION_LOST();
I2CDELAY();
CLRSCL();
}

/* Read a bit from I2C bus */
bool i2c_read_bit(void)
{
bool bit;
/* Let the slave drive data */
READSDA();
I2CDELAY();
/* Clock stretching */
while (READSCL() == 0)
; /* You should add timeout to this loop */
/* SCL is high, now data is valid */
bit = READSDA();
I2CDELAY();
CLRSCL();
return bit;
}

/* Write a byte to I2C bus. Return 0 if ack by the slave */
bool i2c_write_byte(bool send_start, bool send_stop, unsigned char byte)
{
unsigned bit;
bool nack;
if (send_start)
i2c_start_cond();
for (bit = 0; bit < 8; bit++) {
i2c_write_bit((byte & 0x80) != 0);
byte <<= 1;
}
nack = i2c_read_bit();
if (send_stop)
i2c_stop_cond();
return nack;
}

/* Read a byte from I2C bus */
unsigned char i2c_read_byte(bool nack, bool send_stop)
{
unsigned char byte = 0;
unsigned bit;
for (bit = 0; bit < 8; bit++)
byte = (byte << 1) | i2c_read_bit();
i2c_write_bit(nack);
if (send_stop)
i2c_stop_cond();
return byte;
}

Chủ Nhật, 7 tháng 8, 2011 04:20 Đọc tiếp >>

How to write a Network Driver in Linux (Realtek 8139)

Thứ Hai, 27 tháng 6, 2011 / 02:04

Linux Network Interface Driver
This article explains how to write a network interface driver in Linux . There are many network
interface cards available in market. I have taken the Realtek chip driver 8139too.c to explain
code snippets. This driver is implemented in linux/drivers/net/8139too.c file. I have chosen
8139too.c
driver because hardware specifications for Realtek chips are available free and you can download
or read them online .
See References section for download links to Realtek Manuals RTL8139D_DataSheet.pdf ,
RTL8139_ProgrammersGuide.pdf. I suggest you, first read device manuals and then read this
article for better understanding. RTL8139_ProgrammersGuide.pdf explains how the reception
and transmission happen in Realtek 8139 chip where as RTL8139D_DataSheet.pdf explains
register’s details. This article explains the driver from linux 2..6.26 kernel.
I assume that reader is familiar with Linux kernel and PCI devices. Though this article explains
8139too.c driver , writing any other network interface driver is similar except for the hardware
specific functionalities, which change.
This article is divided into 5 parts and I wish to present each part every week to facilitate short,
quick and informative reading.
1) Overview
2) Initialization
3) Packet handling ( reception and transmission)
4) Status and Control
5) Uninitialization
Overview
                                   
In Linux, network drivers have different properties than other drivers like char drivers and block
drivers. Char and block drivers have major and minor number concept . VFS identifies these
drivers using their major and minor numbers and these drivers have files created in /dev directory
with their major and minor numbers . But network drivers do not have any major or minor
number concept and no files created in /dev directory. Network drivers are identified in the
kernel with its interface descriptor block ,struct net_device (defined in
linux/include/linux/netdevice.h). net_device objects of all network drivers are put into a global
liked list and accessed by the kernel whenever it needs. An application cannot access the driver
directly and it should go through the system calls like socket .

As you know, any device can be interfaced with CPU using any bus like PCI , USB, Firewire etc.
Network interface card also can be interfaced with CPU using any of the above said buses .
Network interface card can be inbuilt into mother board or inserted into any bus slot. In this
article we assume that network interface card is a PCI device. When a packet arrives, network
interface card sees the destination MAC address of the packet and puts the packet in input data
buffer(RxRing) if the destination MAC address matches with its MAC address , raises an
interrupt and continue receiving the packets. If Driver wants to send a packet it puts the packet in
output buffer(TxBuffer) . Network interface card takes the packet from TxBuffer and puts that in
its controller’s FIFO buffer and try to send the packet. Once the packet is sent network interface
card raises an interrupt and writes status of the interrupt in its status registers. Any Network
interface driver is responsible for activities in the following areas:
Initialization
Packet Reception
Packet Transmission
Status and Control
Uninitialization

Initialization
The initialization part of a network driver has the responsibility of initializing the driver and
hardware. The following are the some of the responsibilities of initialization part of the driver.
Registering with the Linux low level bus interface subsystem
Allocating interface descriptor block (net_device) ,device specific structure and initializing
media specific fields
Getting device specific structure object pointer
Enabling Network interface card
Getting the Device resources (Memory mapped or port mapped I/O register map)
Getting device MAC address
Initialization of device methods in the net_device
Registering net_device object with the kernel
Registering the interrupt handler (ISR)
Allocating Rxring and Txring
Initializing the hardware (network interface card)
Start the network interface’s transmit Queue

2.1) Registering with the Linux low level bus interface subsystem
Linux provides low level interface to access bus. For PCI devices PCI subsystem is provided.
This provides functions for accessing PCI devices. For USB devices USB subsystem is provided.
The PCI subsystem in the kernel provides all the generic functions that are used in common by
various PCI device drivers to access a PCI device. First step in initialization part of the driver
should be registering with PCI subsystem. Once registration is over PCI subsystem will notify the
driver whenever the device is found on the bus by calling probe function of the driver. The
following code snippet shows registration with PCI subsystem. This code would be written in
initialization routine of the driver module.
static struct pci_device_id rtl8139_pci_tbl[] = {
{0×10ec, 0×8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{}, /*Null terminated entry*/
}
static struct pci_driver rtl8139_pci_driver = {
.name = DRV_NAME,
.id_table = rtl8139_pci_tbl,
.probe = rtl8139_init_one,
.remove = __devexit_p(rtl8139_remove_one),
#ifdef CONFIG_PM
.suspend = rtl8139_suspend,
                                    
.resume = rtl8139_resume,
#endif /* CONFIG_PM */
};
static int __init rtl8139_init_module (void)
{
return pci_register_driver(&rtl8139_pci_driver);
}
To register with the PCI subsystem,the driver should create a struct pci_driver object , fill in the
object and call pci_register_driver function. pci_register_driver function takes one parameter ,
pointer to
an object of type struct pci_driver . The following are some of the fields of pci_driver:
‘name’ field is name of this driver,
‘probe’ field is a call back function which is called whenever your network controller is found on
the PCI bus. It’s prototype is:
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id);
‘id_table’ field is struct pci_device_id pointer which contains the device information
that you are writing driver for. struct pci_device_id has the following definition:
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID’s or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,progif) triplet */
kernel_ulong_t driver_data; /* Data private to the driver */
};
‘vendor’ field is vendor of the any PCI device(in this case network interface card ), ‘device ‘ field
is product or device id of the device , subvendor is subvendor of the device , ‘class’ is class of the
device (see PCI specification for different types classes ), driver_data is a private field that can be
used by driver.
‘remove’ is a call back function which is called whenever network interface card is removed or
                                    
when the driver module is unloaded. Prototype of this function is:
void (*remove) (struct pci_dev *dev)
’suspend ‘ is a call back function which is called whenever device is to be suspended and should
not process any more packets. Prototype of this function is:
int (*suspend) (struct pci_dev *dev, pm_message_t state);
‘resume’ is a call back function which is called by the PCI layer whenever suspended device
wants to be woken up. Prototype of this function is:
int (*resume) (struct pci_dev *dev);
Once the driver creates pci_driver object it is registered with the PCI subsystem using
pci_register_driver function. Whenever our device (network interface card) is found on the bus,
PCI subsystem calls driver’s ‘probe’ function. probe function receives two parameters. One is
pointer to
struct pci_dev object and second is pointer to struct pci_device_id object . Each PCI device is an
object of type struct pci_dev . The following is the 8139too.c probe function.
static int __devinit rtl8139_init_one (struct pci_dev *pdev, onst struct pci_device_id *ent)
c
{
struct net_device *dev = NULL;
struct rtl8139_private *tp;
}
2.2) Allocating interface descriptor block (net_device) ,device specific structure and
initializing media specific fields
Each interface is an object of type struct net_device , called interface descriptor block. Interface
can represent a specific media like Ethernet,Token ring and fddi etc. Interface descriptor block is
a
combination of device specific fields and media specific fields . the following function allocates
interface descriptor block struct net_device.
dev = alloc_netdev(sizeof(*tp),”eth%d”,ether_setup);
This function creates struct net_device object ,allocates space for device specific structure
                                      
s name to this interface as ‘eth%d’ (%d
struct rtl8139_private (first argument) and assign
specifies eth0 for first interface ,eth1 for second interface etc)(second argument).
struct rtl8139_private is a device specific structure .There will be an object of this structure
for each interface found on the network interface card. Each driver will define its own device
specific
structure. struct rtl8139_private definition can be found in 8139too.c file.
Realtek 8139 driver is a Ethernet driver. So we need to initialize Ethernet media specific fields of
n to
struct net_device object . alloc_netdev function calls ether_setup (third argument) functio
initialize the Ethernet media specific fields.
ether_setup is a kernel function which initialize some of the ethernet specific fields . tr_setup
function
can be used to initialize token ring device fields. fddi_setup function can be used for fddi
devices.
These all three tasks , allocating net_device , allocating space for device specific structure and
initializing
media specific fields can also be performed by calling alloc_etherdev media specific function.
The
following code shows that.
dev = alloc_etherdev(sizeof(*tp));
This allocates net_device object ,gives its name as eth%d and initialize ethernet media specific
fields.
For token ring devices you have alloc_trdev and for fddi devices you have alloc_fddidev
functions .
If you want more about struct net_device you can refer Understanding Linux network internals
book.
2.3 Getting device specific structure object pointer
                                    
Memory allocated for the device specific object will be pointed by the ‘priv’ field of the
net_device
object. This can be stored into a local variable using netdev_priv function. Direct accessing of
‘priv’
field is discouraged.
tp = netdev_priv(dev);
This will store the pointer to device specific structure into ‘tp’ local pointer variable.
2.4 Enabling Network Interface Card
At the initialization time , network interface card will be in idle state . we need to enable the
network
interface card by setting enable bit in the command register of the device configuration space.
This can
be done by calling pci_enable_device function.
rc = pci_enable_device(pdev);
if(rc)
goto err_out;
2.5 Getting the Device resources (Memory mapped or Port mapped register map )
To talk to the network interface card , network controller provides some registers. Driver has to
map
these registers into processor address space so that read/write operations by the driverwill be
made on
system memory addresses directly. PCI devices can provide two types of memory mapping, one
is
memory mapped I/O and second is port mapped I/ . O
Details of each register will be explained in the device specification. At the time of device
enumeration,
base address of the registers, some flags and total size of these registers are stored in ‘resources’
field of
the struct pci_dev object. Network interface driver needs to get these details and store them in
device specific structure to be used later. The following code snippet shows this:
                                    
pio_start = pci_resource_start (pdev, 0);
pio_end = pci_resource_end (pdev, 0);
pio_flags = pci_resource_flags (pdev, 0);
pio_len = pci_resource_len (pdev, 0);
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev, 1);
Each PCI device can support upto six base addresses like base address 0,base address 1 etc . One
for
memory mapped ,one for port mapped and etc .For each base address an object of type struct
resource is created and filled with base address ,size and flags . Driver has to read each struct
resource object and get the base address and size and flags..
To get the base address of a device you can use pci_resource_start macro. This macro takes two
parameters , one is pci_dev object of the device that you want base address and another is base
address
register number. Base address register number can be one of 05 numbers.
To get the end of base address you can use pci_resource_end macro,to get size of the registers
you can
use pci_resource_len macro.
To get flags of the device you can use pci_resource_flags macro. Flags can be any of the
following.
IORESOURCE_IO /* Resource type */
IORESOURCE_MEM
IORESOURCE_IRQ
IORESOURCE_DMA
IORESOURCE_PREFETCH
IORESOURCE_READONLY
                                    
IORESOURCE_CACHEABLE
IORESOURCE_RANGELENGTH
IORESOURCE_SHADOWABLE
IORESOURCE_SIZEALIGN /* size indicates alignment */
IORESOURCE_STARTAL IGN /* start field is alignment */
IORESOURCE_DISABLED
IORESOURCE_UNSET
IORESOURCE_AUTO
IORESOURCE_BUSY /* Driver has marked this resource busy */
As a driver developer you need to know only IORESOURCE_IO, IORESOURCE_MEM and
IORESOURCE_BUSY flags. IORESOURCE_IO flags tel s that this base address is port mapped
,
l
IORESOURCE_MEM tells that this base address is memory mapped and
IORESOURCE_BUSY tells
that this resource is reserved by this driver. If resources are reserved, another driver cannot use
these
resources.
Once you got the device resources you need to check them for what type of mapping they are.
The
following code shows that :
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
dev_err(&pdev>dev, “region #0 not a PIO resource, aborting\n”);
rc = ENODEV;
goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
                                   
if (!(mmio_flags & IORESOURCE_MEM)) {
dev_err(&pdev>dev, “region #1 not an MMIO resource, aborting\n”);
rc = ENODEV;
goto err_out;
}
After checking the resources you have to reserve the resources by calling pci_request_regions
function.
This function reserves the resources and returns error if they are already reserved by another
driver.
rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
Some PCI devices have the capability of bus mastering . We need to enable it by calling
pci_set_master
function. This function sets the bus mastering bit of the command register in the device
configuration
space.
/* enable PCI busmastering */
pci_set_master(pdev);
Device resources have to be remapped into the kernel address space so that page tables will be
created
for the registers. For the Port mapped I/O this is done using ioport_map and for memory mapped
I/O
this is done using pci_iomap function. After remapping you need to store base address in the
‘base_addr’ field of net_device object and also store base address and resource length in the
device
specific object to be used later.
#ifdef USE_IO_OPS
ioaddr = ioport_map(pio_start, pio_len);
                                   
if (!ioaddr) {
dev_err(&pdev>dev, “cannot map PIO, aborting\n”);
rc = EIO;
goto err_out;
}
dev>base_addr = pio_start;
tp>mmio_addr = ioaddr;
tp>regs_len = pio_len;
#else
/* ioremap MMIO region */
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
dev_err(&pdev>dev, “cannot remap MMIO, aborting\n”);
rc = EIO;
goto err_out;
}
dev>base_addr = (long) ioaddr;
tp>mmio_addr = ioaddr;
tp>regs_len = mmio_len;
#endif /* USE_IO_OPS */
Once you got resources you need to reset the controller chip. This can be done by setting reset bit
of the
command register of the controller.(see the device specification)
/* Soft reset the chip. */
RTL_W8 (ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i) {
                                   
barrier();
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
break;
udelay (10);
}
RTL_W8 macro definition is:
#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg));
2.6 Getting device MAC address
Driver has to read the MAC address stored in the ROM of the network interface card . To access
ROM
of the network interface card , some of the registers of the memory mapped or port mapped I/O
registers
are used. This details can be found in the device specification.8139too driver calls read_eeprom
local
function to read the MAC address from the ROM of the controller. This MAC address is stored
in the
‘dev_addr’ and ‘perm_addr’ fields of net_device object.
addr_len = read_eeprom (ioaddr, 0,      == 0×8129 ? 8 : 6;
for (i = 0; i <>
((__le16 *) (dev>dev_addr))[i] = cpu_to_le16(read_eeprom (ioaddr, i + 7, addr_len));
memcpy(dev>perm_addr, dev>dev_addr, dev>addr_len);
2.7 Filling device methods in the net_device
Driver has to provide it’s functionalities to the kernel through the device methods of struct
net_device . These are the operations that can be performed on the network interface. Some of
the
function pointers of net_device structure are left blank and some are filled by ‘ether_setup’
function
called at the time of net_device object allocation.
                                      
Driver should fill some basic fundamenta l operations and can leave optional operations.
Fundamental
methods are those that are needed to be able to use the interface; optional methods implement
more
advanced functionalities that are not strictly required.
/* The Rtl8139specific entries in the device structure. */
dev>open = rtl8139_open;
dev>hard_start_xmit = rtl8139_start_xmit;
netif_napi_add(dev, &tp>napi, rtl8139_poll, 64);
dev>stop = rtl8139_close;
dev>get_stats = rtl8139_get_stats;
dev>set_multicast_list = rtl8139_set_rx_mode;
dev>do_ioctl = netdev_ioctl;
dev>ethtool_ops = &rtl8139_ethtool_ops;
dev>tx_timeout = rtl8139_tx_timeout;
dev>watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev>poll_controller = rtl8139_poll_controller;
#endif
‘open ‘ function opens the interface and is called whenever user configures the interface using
any
utilities like ifconfig or ip . This function explained later in detail.
‘hard_start_xmit’ function is called whenever kernel wants to send a packet . This function is
explained later in detail.
‘rtl8139_poll ‘ is called whenever there is an incoming packet to be processed. This function is
explained later in detail.
’stop’ function stops the interface and is called whenever interface is brought down. This
function
                                     
is explained later in detail.
‘get_stats’ is called whenever an application needs to know statistics of the interface . This
function is explained later in detail.
’set_multicast_list’ is an optional method and is called when the multicast list for the device
changes and when the flags change . We are not going to explain this function.
‘do_ioctl’ is interface specific function . This is an optional routine and we are not going to
explain.
‘ethtool_ops’ is a pointer to a structure of type struct ethtool_ops. This structure contains some
function pointers that are used by the ethtool tool. This we are not going to explain.
‘poll_controller’ is called whenever kernel wants to poll for the device status. This function
simply calls drivers interrupt routine to check if the device has anything to say.
After this some of the net_device and device specific object fields are filled .
dev>features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
dev>irq = pdev>irq;
/* tp zeroed and aligned in alloc_etherdev */
tp>mmio_addr = ioaddr;
‘features’ field of net_device object tells the capabilities of the driver like it support scatter gather
I/O ,check sum can be calculated in hardware and can DMA to high memory etc.’irq’ field of
net_device
object contains irq number of this controller.
2.8 Registering net_device object with kernel
Driver has to register with the kernel by giving net_device object . All net_device objects of all
interfaces are put into linked lists and accessed by the kernel whenever it needs. Network driver
can
register with the kernel using register_netdev function.
i = register_netdev(dev);
register_netdev function takes a completed net_device object and adds it to the kernel interfaces.
                                     
0 is returned on success and a negative error no code is returned on a failure to set up the device,
or if
the name is a duplicate.
struct net_device object is stored in struct pci_dev object so that it can be accessed later.
This is done with pci_set_drvdata function.
pci_set_drvdata(pdev , dev);
} /*end of rtl8139_init_one function */
/*start of open function */
static int rtl8139_open (struct net_device *dev)
{
open function is called by the kernel whenever this network interface is configured by admin
using any
user space utilities like ifconfig or ip .When ifconfig is used to assign an address to the interface,
it
performs two tasks. First, it assigns the address by means of ioctl(SIOCSIFADDR) (Socket I/O
Control
Set Interface Address). Then it sets the IFF_UP bit in dev>flag by means of
ioctl(SIOCSIFFLAGS) (Socket I/O Control Set Interface Flags) to turn the interface on.
open function receives net_device object as its parameter. Driver should get the device specific
object which is stored in the ‘priv’ field of net_device object at the time of net_device object
allocation. This can be done by calling netdev_priv inline function.
struct rtl8139_private *tp = netdev_priv(dev);
/* get registers base address in a local variable */
void __iomem *ioaddr = tp>mmio_addr;
2.9 Registering Interrupt handler (ISR)
Whenever a packet is received or a packet is sent an interrupt is raised by the network controller.
Driver
needs to register an interrupt handler(ISR ) and this handler is called whenever controller raises
an
                                    
interrupt. Driver can register the interrupt handler either in driver’s init routine or in the open
function .
Driver registers with interrupt handler using request_irq routine.
retval = request_irq (dev>irq, rtl8139_interrupt, IRQF_SHARED, dev>name, dev);
if (retval)
return retval;
request_irq routine takes five parameters. First parameter is irq number of the device , second
parameter
is interrupt handler (ISR) ,Third parameter is irqflags,fourth parameter is device name and last
parameter
is dev_id. ‘dev_id’ feild can be of any object pointer ,is necessary if irqflags is IRQF_SHARED
and
used at the time of freeing the ISR using free_irq routine. Generally this field will be a pointer to
net_device instance and is used at the time of interrupt handler execution. Interrupt handler has
the
following prototype:
irqreturn_t (*irq_handler_t)(in t, void *)
and irqflags can be any of the following.
* IRQF_DISABLED keep irqs disabled when calling the action handler
* IRQF_SAMPLE_RANDOM irq is used to feed the random generator
* IRQF_SHARED allow sharing the irq among several devices
* IRQF_PROBE_SHARED set by callers when they expect sharing mismatches to
occur
* IRQF_TIMER Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU Interrupt is per cpu
* IRQF_NOBALANCING lag to exclude this interrupt from irq balancing
F
* IRQF_IRQPOLL Interrupt is used for polling (only the interrupt that is registered first
                                     
in an shared interrupt is considered for performance reasons)
request_irq routine allocates interrupt resources and enables the interrupt line and IRQ handling.
From
the point this call is made driver handler function may be invoked. Since driver handler function
must
clear any interrupt the board raises, driver must take care both to initialize the hardware and to set
up
the interrupt handler in the right order.
We will describe functionalities of interrupt handler(ISR) later in this article.
2.10 Allocating Rxring and Txbuffer
Whenever network controller receives a packet it puts that in a receive buffer called RxRing and
raises an
interrupt and continue to receive next packet. Driver puts outgoing packets in Txbuffer and
network
controller takes the packets from the Txbuffer , sends them out of the wire and raises interrupt.
We will
describe this process later in detail. Driver allocates Rxring and Txbuffer using
dma_alloc_coherent
routine. If Memory allocated for the buffers ,the by dma_free_coherent routine returns virtual
address
of the buffers .
tp>tx_bufs = dma_alloc_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
&tp>tx_bufs_dma, GFP_KERNEL);
tp>rx_ring = dma_alloc_coherent(&tp>pci_dev>dev, X_BUF_TOT_LEN, R
&tp>rx_ring_dma, GFP_KERNEL);
if (tp>tx_bufs == NULL || tp>rx_ring == NULL) {
free_irq(dev>irq, dev);
if (tp>tx_bufs)
dma_free_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
tp>tx_bufs, tp>tx_bufs_dma);
                                     
if (tp>rx_ring)
dma_free_coherent(&tp>pci_dev>dev,RX_BUF_TOT_LEN,
tp>rx_ring, tp>rx_ring_dma);
return ENOMEM;
}
dma_alloc_coherent routine takes four parameters. First is generic device struct device object ,
second is length of the buffer ,third is an output param of type dma_addr_t which is filled with
physical
address (bus address) of the allocated memory and fifth is GFP flag which tells how the memory
should
be allocated..This function returns virtual address of the memory allocated.
2.11 Initialize the hardware (network interface card)
Network driver has to initialize network controller at the time of open function is called.
Controller
initialization includes, resetting the chip , restoring MAC address in the chip register enabling ,
reception(rx) and transmission by setting rxenable and txenable bits in command register of the
controller,setting transfer thresholds , initializing transmission descriptors and reception
descriptor of the
controller with the physical addresses of the Txbuffer and RxRing,setting what type of packets to
be
received by setting in RxConfig and TxConfig registers, and enabling interrupts by setting
Interrupt
Mask Register(IMR) .
1 Soft reset the chip
RTL_W8 (ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i) {
barrier();
if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
                                    
break;
udelay (10);
}
2 Restore the MAC address
RTL_W32_F (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev>dev_addr + 0)));
RTL_W32_F (MAC0 + 4, le16_to_cpu (*(__le16 *) (dev>dev_addr + 4)));
3 Enable transmission and reception
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
4 Set type of packets to be received
RTL_W32 (RxConfig, tp>rx_config);
RTL_W32 (TxConfig, rtl8139_tx_config);
5 initialize reception buffer descriptor(RxBuf) with RxRing DMA address(bus address).This s
i
where physical address used.
RTL_W32_F (RxBuf, tp>rx_ring_dma);
6 Initialize transmission descriptors with Txbuffer DMA address (bus address)
for (i = 0; i <>
RTL_W32_F (TxAddr0 + (i * 4), tp>tx_bufs_dma + (tp>tx_buf[i] tp>tx_bufs));
7 Enable all known interrupts by setting the interrupt mask register
RTL_W16 (IntrMask, rtl8139_intr_mask);
2.12 Start the network interface’s transmit Queue
The open function should also start the interface’s transmit queue (allowing it to accept packets
for
transmission) once it is ready to start sending data. Driver should call kernel function
netif_start_queue
to start queue.
netif_start_queue (dev);
                                      
netif_start_queue takes net_device object as its parameter and returns nothing. This function
simply
sets a bit in ’state’ field of net_device object that allows upper layers to call the device
hard_start_xmit function .
}/ * end of open function */
3 Packet handling
Packet handling is a task of performing transmission and reception of packets. Packet handling is
most
important task of any network interface driver. in kernel discussions, transmission refers only to
sending
frames outward, whereas reception refers to frames coming in.
Before going to see how transmission and reception happen we will see the role of interrupts in
network
drivers. Kernel can use two main techniques for exchanging data: pol ing and interrupts. There is
also an
l
option of combination of these two techniques.
Polling is a technique where the kernel constantly keeps checking whether the device has
anything to
say. It can do that by continually reading a memory register on the device, for instance, or
returning to
check it when a timer expires.
Interrupts is another technique technique of exchanging data. Here the device driver, on behalf of
the
kernel, instructs the device to generate a hardware interrupt when specific events occur. The
kernel,
interrupted from its other activities, will then invoke a handler registered by the driver to take
care of the
device’s needs. Interrupts can be raised by the device when frame is received and when a frame is
transmitted .. If this is the reception of a frame, the handler queues the frame somewhere and
notifies the
                                     
kernel about it and if it is transmission the handler updates its status.
The code that takes care of an input frame is split into two parts: first the driver
copies the frame into an
input queue accessible by the kernel, and then the kernel processes it (usually passing it to a
handler
dedicated to the associated protocol such as IP). The first part is executed in interrupt context and
second
part is executed in the bottom half ..Second part may interrupted by the first because interrupt
context
has the higher priority than bottom half . More about bottom halves can be read in Understanding
Linux
Kernel and Understanding Linux network internals books.
Multiple Frames also can be processed During an Interrupt. This approach is used by quite a few
Linux
device drivers. When an interrupt is notified and the driver handler is executed, the latter keeps
downloading frames and queuing them to the kernel input queue, up to a maximum number of
frames
TimerDriven Interrupts technique is an enhancement to the previous ones. Instead of having the
device
asynchronously notify the driver about frame receptions, the driver instructs the device to
generate an
interrupt at regular intervals. The handler will then check if any frames have arrived since the
previous
interrupt, and handles all of them in one shot.
Combination of all above said techniques is also possible . A good combination would use the
interrupt
technique under low load and switch to the timerdriven interrupt under high load.
Pros and cons of all above said and more detail description of above said techniques can be
found in
Understanding Linux Network Internals book by Christian Benvenuti.
3.1 Packet Reception
                                    
When a packet arrives into the network interface card , network controller checks the destination
MAC
address of the packet. if it matches with its MAC address or if it is broadcast address network
interface
card copies the packet into receive buffer(Rxring) and raises an interrupt.
Receive buffer(Rxrinf) is a block of I/O memory allocated by the river . Network interface card
will
d
have a receive buffer descriptor register and a receive buffer status register. Driver has to write
Physical
address of the receive buffer allocated into the receive buffer descriptor register. This process is
specific
to hardware and is provided in the device manual. Some devices provide some receive block
descriptors,a structure,that contains status of the each packet , buffer pointer and size of packets
etc.
Driver has to allocate a buffer and physical address of this is put in the buffer pointer .
When a packet is received by the network interface card, it adds a packet header before the
packet , puts
the packet in receive buffer(Rxring) and raises interrupt. This is specific to Realtek 8139 chips
and see
device specification.
When the interrupt is raised , driver interrupt handler(ISR) gets called. Driver interrupt handler
has to
check the interrupt status register(ISR) of the device what the interrupt is raised for and has to
take
appropriate action. In the case of reception ,reception bit of interrupt status register is set. Now
we will
see step by step what interrupt handler does:
3.1.1 Interrupt handler of the driver:
Interrupt handler is called when a packet is received or transmitted. Kernel will send two
arguments to
                                    
this function . One is irq number and other is dev_id which is sent as last parameter of
request_irq
function at the time of interrupt handler registration. Generally this is a pointer to net_device
object.
As i said, driver has to check status register of the network interface card and should take action
accordingly. In the case of packet reception , driver should schedule a bottom half and return
from
interrupt handler. The next step of processing of packet is done by the kernel in the bottom half.
In the
bottom half, kernel calls driver’s poll function to do the later processing of packet.
static irqreturn_t rtl8139_interrupt (int irq, void *dev_id)
{
1 Get net_device object from the dev_id
struct net_device *dev = (struct net_device *) dev_id;
2 Get device specific structure object from the net_device. This is stored in the ‘priv’ field of
net_device. Use netdev_priv inline function to get pointer to that and store registers base
address into a local variable ‘ioaddr’ .
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
3 Get interrupt status register (ISR) of the controller into a local variable
status = RTL_R16 (IntrStatus);
4 Irq numbers in PCI devices can be shared by many devices. So many devices might have been
registered interrupt handler on the same irq number . Driver has to confirm that interrupt has
been raised by its interface card . This can be done by checking interrupt status register for
any pending interrupts by the interface card.
/* shared irq? */
if (unlikely((status & rtl8139_intr_mask) == 0))
goto out;
                                     
5 Check if the device is present or not (hot pluggable) or if there is major problem.
if (unlikely(status == 0xFFFF))
goto out;
6 Driver has to acknowledge the interrupts by clearing appropriate bits in the interrupt status
register (ISR)
ackstat = status & ~(RxAckBits | TxErr);
if (ackstat)
RTL_W16 (IntrStatus, ackstat);
7 As i said , receive packets are processed by poll function vector in the bottom handler.
Network uses softirq NET_ RX_SOFTIRQ bottom half for input packets. Driver should
schedule the bottom half and finish the interrupt handler. netif_rx_schedule is used to enable
NET_RX_SOFTIRQ bottom half. This functions takes two parameters, one is net_device
object and other is an object of type struct napi_struct . This structure has the
following definition.
struct napi_struct {
/* The poll_list must only be managed by the entity which
* changes the state of the NAPI_STATE_SCHED bit. This means
* whoever atomically sets that bit can add this napi_struct
* to the percpu poll_list, and whoever clears that bit
* can remove from the list right before clearing the bit.
*/
struct list_head poll_list;
unsigned long state;
int weight;
int (*poll)(struct napi_struct *, int);
#ifdef CONFIG_NETPOLL
                                     
spinlock_t poll_lock;
int poll_owner;
struct net_device *dev;
struct list_head dev_list;
#endif
};
This object is filled at the time of function pointers assignment, using netif_napi_add
function.
The following code checks status of the interrupt and calls netif_rx_schedule to
enable the bottom half. netif_rx_schdule function first tests if poll needs to be scheduled
using netif_rx_schedule_prep, is scheduled only if network interface up and next calls
__netif_rx_schedule to schedule poll .
if (status & RxAckBits)
netif_rx_schedule(dev, &tp>napi);
8 return from the interrupt handler. (we will see transmission part of interrupt handler later in
Packet transmission section )
return IRQ_RETVAL(handled);
} /* end of interrupt handler routine */
3.1.2 NET_RX_SOFTIRQ softirq calls driver’s poll method
Kernel calls poll method of the driver in the NET_RX_SOFTIRQ softirq bottom half to process
the
input packet . This softirq was scheduled in interrupt handler routine.
poll method receives two parameters, one is pointer to struct napi_struct object and second is
‘budget’. napi_struct object is the object which was created at the time of initialization of
methods in
the net_device object .’budget’ field is the maximum number of packets the kernel can accept at
this
                                    
time or we can say that the ‘budget’ value is a maximum number of packets that the current CPU
can
receive from all interfaces.
The following is the 8139too.c driver poll method. It checks for the interrupt status register and
calls
rtl8139_rx local function to do the rest of the process.
static int rtl8139_poll(struct napi_struct *napi, int budget)
{
1 Get device specific structure object. ‘napi’ is a field of type stuct napi_struct in device
specific structure struct rtl8139_private. If we know the address of ‘napi’ field of
struct rtl8139_private we can find the starting address of the struct
rtl8139_private object using container_of function.
struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi);
2 Get net_device object from the struct rtl8139_private object and store register
base address into a local variable.
struct net_device *dev = tp>dev;
void __iomem *ioaddr = tp>mmio_addr;
3 Check if it was the receive interrupt and call rtl8139_rx local function. rtl8139_rx returns
number of packets received. This function is explained below.
if (likely(RTL_R16(IntrStatus) & RxAckB its))
work_done += rtl8139_rx(dev, tp, budget);
4 If number of packets received is less than budget , reenable receive interrupts by setting the
interrupts mask regsiter(IMR) and all __netif_rx_complete function to turn of polling.
c
RTL_W16_F(IntrMask, rtl8139 _intr_mask);
__netif_rx_complete(dev, napi);
__netif_rx_complete function removes this interface from the polling list.
                                    
5 Return number of packets received
return work_done;
} /*end of rtl8139_poll method*/
A received packet is put into a structure struct sk_buff called socket buffer. This structure is the
main encapsulation of a packet and contains pointers to point different layer headers in the packet
and
pointers to input ,output interfaces . More about this structure can be read in Understanding
Linux
network internals book.
Driver has to take the packet from the RxRing , copy that into sk_buff object and give it to the
kernel.
rtl8139_rx local function will do that. This function receives three parameters , one is pointer to
net_device object ,second is pointer to device specific object struct rtl8139_private and last is
‘budget’.
static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, int budget)
{
void __iomem *ioaddr = tp>mmio_addr;
int received = 0;
1 Get pointer to RxRing
unsigned char *rx_ring = tp>rx_ring;
2 Get current packet offeset (see device specification)
unsigned int cur_rx = tp>cur_rx;
3 Now the driver should run in a loop and take the each packet from the RxRing . The loop
should run until three conditions are satisfied . Three conditions are network interface should be
up, received packets should be less than the ‘budget’ and the RxRing is not empty.
while (netif_running(dev) && received <>
&& (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
struct sk_buf *skb;
                                    
4 Get the packet offset into the RxRing
u32 ring_offset = cur_rx % RX_BUF_LEN;
5 Get the packet header ( See device Manual) and find packet size. Note that packet size is
receive packet size minus 4( 4 is CRC)
/* read size+status of next frame from DMA ring buffer */
rx_status = le32_to_cpu (*(__le32 *) (rx_ring + ring_offset));
rx_size = rx_status >> 16; /*receive packet size from packet header*/
pkt_size = rx_size – 4; /* packet size */
6 Allocate struct sk_buff object.
skb = dev_alloc_skb (pkt_size + 2);
7 Copy packet into sk_buff . This will copy packet into ‘data’ field of sk_buff
skb_copy_to_linear_data (skb, &rx_ring[ring_offset + 4], pkt_size);
8 Set ‘protocol’ field of sk_buff to appropriate packet type. This is ‘type’ of ethernet
frame. Call eth_type_trans to get the packet type. For token ting devices you can use
tr_type_trans function.
skb>protocol = eth_type_trans ( skb, dev);
9 Update statistics
tp>stats.rx_bytes += pkt_size;
tp>stats.rx_packets++;
10 Give the skb to kernel
netif_receive_skb (skb);
received ++;
} /* end of while*/
tp>cu_rx = cur_rx;
return received;
}
                                   
netif_running inline function tests if the interface is up and running. It checks if
__LINK_STATE_START bit of ’status’ field of et_device object is set. dev_alloc_skb function
n
allocates memory for sk_buff from the cache and fills some the fields. netif_receive_skb is
main receive data processing function.
3.2 Packet Transmission
When the kernel has packets to send out of the interface ,it calls driver’s hard_start_xmit method.
hard_start_xmit function receives two parameters ,one is sk_buff of the packet to be transmitted
and
another is net_device object .
sk_buff of the trasmitted packet is filled by the upper layers. ‘data’ field of sk_buff contains
packet to be sent. Driver should extract packet from the sk_buff and put that into TxBuffers.
Then
driver should write length of packet and threshold in the Transmission descriptor status register
of the
device . Then the device takes the packet from the Txbuffers and sends it.
Now we will describe rtl8139_start_xmit(hard_start_xmit) function of 8139too driver.
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem ioaddr = tp>mmio_addr; /*register base address */
unsigned int len = skb>len; /* length of the packet */
1 Calculate the next Tx descriptor entry
entry = tp>cur_tx % NUM_TX_DESC;
2 Copy the packet into TxBuffer
skb_copy_and_csum_dev(skb, tp>tx_buf[entry]);
3 Free the socket buffer sk_buff
dev_kfree_skb(skb);
                                   
4 Writer length of packet and threshold in Transmission descripor status register
RTL_W32_F (TxStatus0 + entry * sizeof (u32)),
(
tp>tx_flag | max(len, (unsigned int)ETH_ZLEN));
} /* end of tl8139_start_xmit */
Network interface card will take the packet from the TxBuffer and puts that in it’s FIFO. Once
the FIFO
reached threshold value set by the driver it sends the packet. After sending the packet network
interface
card will raise an interrupt. Driver’s interrupt handler will be called.
Driver’s interrupt handler should check why the interrupt has occurred and if it is transmission
interrupt it
updates its statistics. The following code shows how rtl8139too driver will handle the
transmission
interrupt.
static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
status = status = RTL_R16 (IntrStatus);
1 Check if the interrupt is transmission interrupt and call rtl8139_tx_interrupt local
function.
if (status & (TxOK | TxErr)) {
rtl8139_tx_interrupt (dev, tp, ioaddr);
if (status & TxErr)
RTL_W16 (IntrStatus, TxErr);
} /* end of rtl8139_interrupt */
                                    
static void rtl8139_tx_interrupt (struct net_device *dev, struct rtl8139_private *tp,
void __iomem *ioaddr)
{
1 Read transmission descriptor status register and see what the status of the packet.
txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
2 Increment error statistics if there are any problems in the transmission
if (txstatus & (TxOutOfWindow | TxAborted)) {
tp>stats.tx_errors++;
if (txstatus & TxAborted) {
tp>stats.tx_aborted_errors++;
RTL_W32 (TxConfig, TxClearAbt);
RTL_W16 (IntrStatus, TxErr);
}
if (txstatus & TxCarrierLost)
tp>stats.tx_carrier_errors++;
if (txstatus & TxOutOfWindow)
tp>stats.tx_window_errors++;
}
3 Increment statistics of successful transmitted packets
else {
tp>stats.collisions += (txstatus >> 24) & 15;
tp>stats.tx_bytes += txstatus & 0×7ff;
tp>stats.tx_packets++;
}
4 start the transmission queue allowing kernel to call driver’s hard_start_xmit method
again.
                                    
netif_wake_queue (dev);
}/* End of rtl8139_tx_interrupt */
4 Status and Control
4.1 When kernel wants to stop interface it calls stop method of driver
When kernel wants to stop interface it calls stop function of driver. This is called ,for example,
when the
interface is brought down by using any utilities like ifconfig. Responsibility of this function is
would be
exactly opposite to what we have done in open method. Some of the responsibilities include
freeing
receive and transmission buffers , freeing irq and stopping transmission queue etc.
stop takes struct net_device object as its parameter. The following code shows how 8139too.c
implements stop method.
static int rtl8139_close (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
unsigned long flags;
1 stop transmission queue. Once transmission queue is stopped kernel cannot send any more
packets to the driver
netif_stop_queue(dev);
2 Prevent poll function to be scheduled .
napi_disable(&tp>napi);
3 Stop the chip’s Transmission and reception DMA processes . This can be done by writing 0
into
command register of device.
RTL_W8 (ChipCmd, 0);
4 Disable interrupts by clearing the interrupt mask register(IMR).
                                     
RTL_W16 (IntrMask, 0);
5 wait for pending IRQ handlers (on other CPUs) to be completed. This can be done using
synchronize_irq function.
synchronize_irq (dev>irq);
6 Unregister the interrupt handler (ISR)
free_irq(dev>irq,dev);
free_irq function removes an interrupt handler. The handler is removed and if the interrupt line
is no longer in use by any driver it is disabled. On a shared IRQ the driver must ensure the
interrupts are disabled by clearing interrupt mask register on the card it drives before calling
this function. This function does not return until any executing interrupts for this IRQ have
completed. This function must not be called from interrupt context. This function takes two
parameters one is irq line that is to be freed and second is ‘dev_id’ which is sent as last argument
to request_irq function.
7 Free receive(RxRing) and transmission(TxBuffer) buffers .
dma_free_coherent(&tp>pci_dev>dev,RX_BUF_TOT_LEN,
tp>rx_ring, tp>rx_ring_dma);
dma_free_coherent(&tp>pci_dev>dev,TX_BUF_TOT_LEN,
tp>tx_bufs, tp>tx_bufs_dma);
tp>rx_ring = NULL;
tp>tx_bufs = NULL;
return 0;
}
When Application wants statistics of the interface, drivers’s get_stats
4.
method is called
Whenever an application needs to get statistics for the interface, get_stats method of driver is
called. This
                                       
happens, for example, when ifconfig or netstat i is used by the user.
This function receives struct net_device object as its parameter and returns struct
net_device_stats object. Driver has to fill in the struct net_device_stats object with
interface statistics stored in device specific structure rtl8139_private and return it. The
following is the get_stats implementation of 8139too.c driver.
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp>mmio_addr;
/*return statistics stored in ’stats’ field of device specific object*/
return &tp>stats;
}
5 Uninitialization
5.1 remove function of pci_driver (pci remove function)
pci_driver ’s remove method is called whenever network interface card is removed or when the
driver module is unloaded. Functionalities of this driver includes unregistering the net_device
with
the kernel and disabling the network interface card,freeing resources etc . remove function takes
pci_dev object as its parameter and returns nothing.
static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
{
1 Get net_device object from pci_dev object. We have stored net_device object in
pci_dev object by calling pci_set_drvdata in probe method of the driver.
struct net_device *dev = pci_get_drvdata (pdev);
2 flush if there are any packets to be transmitted yet. This can be done using
flush_scheduled_work function. flush_scheduled_work function starts the work queue
rtl8139_thread ,that is created at the time of probe function.
                                  
flush_scheduled_work();
3 Unregister the net_device object with kernel
unregister_netdev (dev);
4 Free IO Resources and net_device object
__rtl8139_cleanup_dev (dev);
5 Disable the network interface card .
pci_disable_device (pdev);
}
static void __rtl8139_cleanup_dev (struct net_device *dev)
{
struct rtl8139_private *tp = netdev_priv(dev);
struct pci_dev *pdev;
pdev = tp>pci_dev;
1 Remove kernel page tables for IO resources
#ifdef USE_IO_OPS
if (tp>mmio_addr)
ioport_unmap (tp>mmio_addr);
#else
if (tp>mmio_addr)
pci_iounmap (pdev, tp>mmio_addr);
#endif /* USE_IO_OPS */
2 Release reserved PCI I/O and memory resources. These resources were previously reserved by
pci_request_regions function. This function takes pci_dev object as its parameter.
pci_release_regions (pdev);
3 Free net_device object using free_netdev function. free_netdev function does the last stage of
destroying an allocated device interface. The reference to the device object is released.
                                   
free_netdev(dev);
}
5.2 Unregistering driver with the low level bus interface (PCI Subsystem)
Last step in the network driver development will be unregistering with low level bus interface ,in
this
case PCI subsystem. Driver can unregister with PCI subsystem using pci_unregister_driver
function.
This function takes pci_driver object as its parameter.
Unregistering will be done in driver module’s cleanup routine.
static void __exit rtl8139_cleanup_module (void)
{
pci_unregister_driver (&rtl8139_pci_driver);
}
References:
1) PCI Local Bus specification
2) Device specifications (RTL8139D_DataSheet.pdf , RTL8139_ProgrammersGuide.pdf)
3) Understanding Linux Network Internals by By Christian Benvenu ti
4) Linux source code
Thứ Hai, 27 tháng 6, 2011 02:04 Đọc tiếp >>