1 /**************************************************************************
2 Etherboot - BOOTP/TFTP Bootstrap Program
3 Skeleton NIC driver for Etherboot
4 ***************************************************************************/
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2, or (at
10 * your option) any later version.
13 /* to get some global routines like printf */
14 #include "etherboot.h"
15 /* to get the interface to the body of the program */
17 /* Drag in support for whichever bus(es) we want for this NIC */
25 * NIC specific static variables go here. Try to avoid using static
26 * variables wherever possible. In particular, the I/O address can
27 * always be accessed via nic->ioaddr.
31 * If you have large static variables (e.g. transmit and receive
32 * buffers), you should place them together in a single structure and
33 * mark the structure as "shared". This enables this space to be
34 * shared between drivers in multi-driver images, which can easily
35 * reduce the runtime size by 50%.
38 #define SKEL_RX_BUFS 1
39 #define SKEL_TX_BUFS 1
40 #define SKEL_RX_BUFSIZE 0
41 #define SKEL_TX_BUFSIZE 0
42 struct skel_rx_desc {};
43 struct skel_tx_desc {};
45 struct skel_rx_desc rxd[SKEL_RX_BUFS];
46 unsigned char rxb[SKEL_RX_BUFS][SKEL_RX_BUFSIZE];
47 struct skel_tx_desc txd[SKEL_TX_BUFS];
48 unsigned char txb[SKEL_TX_BUFS][SKEL_TX_BUFSIZE];
52 * Don't forget to remove "__unused" from all the function parameters!
56 /**************************************************************************
57 * CONNECT - Connect to the network
58 **************************************************************************
60 static int skel_connect ( struct nic *nic __unused ) {
62 * Connect to the network. For most NICs, this will probably
63 * be a no-op. For wireless NICs, this should be the point at
64 * which you attempt to join to an access point.
66 * Return 0 if the connection failed (e.g. no cable plugged
73 /**************************************************************************
74 * TRANSMIT - Transmit a frame
75 **************************************************************************
77 static void skel_transmit ( struct nic *nic __unused,
78 const char *dest __unused,
79 unsigned int type __unused,
80 unsigned int size __unused,
81 const char *packet __unused ) {
82 /* Transmit packet to dest MAC address. You will need to
83 * construct the link-layer header (dest MAC, source MAC,
87 unsigned int nstype = htons ( type );
88 memcpy ( <tx_buffer>, dest, ETH_ALEN );
89 memcpy ( <tx_buffer> + ETH_ALEN, nic->node_addr, ETH_ALEN );
90 memcpy ( <tx_buffer> + 2 * ETH_ALEN, &nstype, 2 );
91 memcpy ( <tx_buffer> + ETH_HLEN, data, size );
92 <transmit_data> ( <tx_buffer>, size + ETH_HLEN );
96 /**************************************************************************
97 * POLL - Wait for a frame
98 **************************************************************************
100 static int skel_poll ( struct nic *nic __unused, int retrieve __unused ) {
101 /* Work out whether or not there's an ethernet packet ready to
102 * read. Return 0 if not.
105 if ( ! <packet_ready> ) return 0;
108 /* retrieve==0 indicates that we are just checking for the
109 * presence of a packet but don't want to read it just yet.
112 if ( ! retrieve ) return 1;
115 /* Copy data to nic->packet. Data should include the
116 * link-layer header (dest MAC, source MAC, type).
117 * Store length of data in nic->packetlen.
118 * Return true to indicate a packet has been read.
121 nic->packetlen = <packet_length>;
122 memcpy ( nic->packet, <packet_data>, <packet_length> );
126 return 0; /* Remove this line once this method is implemented */
129 /**************************************************************************
130 * IRQ - handle interrupts
131 **************************************************************************
133 static void skel_irq ( struct nic *nic __unused, irq_action_t action ) {
134 /* This routine is somewhat optional. Etherboot itself
135 * doesn't use interrupts, but they are required under some
136 * circumstances when we're acting as a PXE stack.
138 * If you don't implement this routine, the only effect will
139 * be that your driver cannot be used via Etherboot's UNDI
140 * API. This won't affect programs that use only the UDP
141 * portion of the PXE API, such as pxelinux.
147 /* Set receive interrupt enabled/disabled state */
149 outb ( action == ENABLE ? IntrMaskEnabled : IntrMaskDisabled,
150 nic->ioaddr + IntrMaskRegister );
154 /* Force NIC to generate a receive interrupt */
156 outb ( ForceInterrupt, nic->ioaddr + IntrForceRegister );
162 /**************************************************************************
163 * OPERATIONS TABLE - Pointers to all the above methods
164 **************************************************************************
166 static struct nic_operations skel_operations = {
167 .connect = skel_connect,
168 .transmit = skel_transmit,
173 /**************************************************************************
174 * PROBE - Look for an adapter
176 * You need to define a probe routine and a disable routine for each
177 * bus type that your driver supports, together with tables that
178 * enable Etherboot to identify that your driver should be used for a
181 * Delete whichever of the following sections you don't need. For
182 * example, most PCI devices will only need the PCI probing section;
183 * ISAPnP, EISA, etc. can all be deleted.
185 * Some devices will need custom bus logic. The ISA 3c509 is a good
186 * example of this; it has a contention-resolution mechanism that is
187 * similar to ISAPnP, but not close enough to use the generic ISAPnP
188 * code. Look at 3c509.c to see how it works.
190 **************************************************************************
193 /**************************************************************************
194 * PCI PROBE and DISABLE
195 **************************************************************************
197 static int skel_pci_probe ( struct nic *nic, struct pci_device *pci ) {
199 pci_fill_nic ( nic, pci );
201 /* Test for physical presence of NIC */
204 DBG ( "Could not find NIC: my explanation\n" );
209 /* point to NIC specific routines */
210 nic->nic_op = &skel_operations;
214 static void skel_pci_disable ( struct nic *nic __unused,
215 struct pci_device *pci __unused ) {
216 /* Reset the card to its initial state, disable DMA and
221 static struct pci_device_id skel_pci_nics[] = {
222 PCI_ROM ( 0x0000, 0x0000, "skel-pci", "Skeleton PCI Adapter" ),
225 PCI_DRIVER ( skel_pci_driver, skel_pci_nics, PCI_NO_CLASS );
227 DRIVER ( "SKEL/PCI", nic_driver, pci_driver, skel_pci_driver,
228 skel_pci_probe, skel_pci_disable );
230 /**************************************************************************
231 * EISA PROBE and DISABLE
232 **************************************************************************
234 static int skel_eisa_probe ( struct nic *nic, struct eisa_device *eisa ) {
236 eisa_fill_nic ( nic, eisa );
237 enable_eisa_device ( eisa );
238 nic->irqno = 0; /* No standard way to get irq from EISA cards */
240 /* Test for physical presence of NIC */
243 DBG ( "Could not find NIC: my explanation\n" );
248 /* point to NIC specific routines */
249 nic->nic_op = &skel_operations;
253 static void skel_eisa_disable ( struct nic *nic __unused,
254 struct eisa_device *eisa ) {
255 /* Reset the card to its initial state, disable DMA and
258 disable_eisa_device ( eisa );
261 static struct eisa_id skel_eisa_nics[] = {
262 { "Skeleton EISA Adapter", EISA_VENDOR('S','K','L'), 0x0000 },
265 EISA_DRIVER ( skel_eisa_driver, skel_eisa_nics );
267 DRIVER ( "SKEL/EISA", nic_driver, eisa_driver, skel_eisa_driver,
268 skel_eisa_probe, skel_eisa_disable );
270 ISA_ROM ( "skel-eisa", "Skeleton EISA Adapter" );
272 /**************************************************************************
273 * ISAPnP PROBE and DISABLE
274 **************************************************************************
276 static int skel_isapnp_probe ( struct nic *nic,
277 struct isapnp_device *isapnp ) {
279 isapnp_fill_nic ( nic, isapnp );
280 activate_isapnp_device ( isapnp );
282 /* Test for physical presence of NIC */
285 DBG ( "Could not find NIC: my explanation\n" );
290 /* point to NIC specific routines */
291 nic->nic_op = &skel_operations;
295 static void skel_isapnp_disable ( struct nic *nic __unused,
296 struct isapnp_device *isapnp ) {
297 /* Reset the card to its initial state, disable DMA and
300 deactivate_isapnp_device ( isapnp );
303 static struct isapnp_id skel_isapnp_nics[] = {
304 { "Skeleton ISAPnP Adapter", ISAPNP_VENDOR('S','K','L'), 0x0000 },
307 ISAPNP_DRIVER ( skel_isapnp_driver, skel_isapnp_nics );
309 DRIVER ( "SKEL/ISAPnP", nic_driver, isapnp_driver, skel_isapnp_driver,
310 skel_isapnp_probe, skel_isapnp_disable );
312 ISA_ROM ( "skel-isapnp", "Skeleton ISAPnP Adapter" );
314 /**************************************************************************
315 * MCA PROBE and DISABLE
316 **************************************************************************
318 static int skel_mca_probe ( struct nic *nic,
319 struct mca_device *mca ) {
321 mca_fill_nic ( nic, mca );
323 /* MCA parameters are available in the mca->pos[] array */
325 nic->ioaddr = ( mca->pos[xxx] << 8 ) + mca->pos[yyy];
326 nic->irqno = mca->pos[zzz] & 0x0f;
329 /* Test for physical presence of NIC */
332 DBG ( "Could not find NIC: my explanation\n" );
337 /* point to NIC specific routines */
338 nic->nic_op = &skel_operations;
342 static void skel_mca_disable ( struct nic *nic __unused,
343 struct mca_device *mca __unused ) {
344 /* Reset the card to its initial state, disable DMA and
349 static struct mca_id skel_mca_nics[] = {
350 { "Skeleton MCA Adapter", 0x0000 },
353 MCA_DRIVER ( skel_mca_driver, skel_mca_nics );
355 DRIVER ( "SKEL/MCA", nic_driver, mca_driver, skel_mca_driver,
356 skel_mca_probe, skel_mca_disable );
358 ISA_ROM ( "skel-mca", "Skeleton MCA Adapter" );
360 /**************************************************************************
361 * ISA PROBE and DISABLE
363 * The "classical" ISA probe is split into two stages: trying a list
364 * of I/O addresses to see if there's anything listening, and then
365 * using that I/O address to fill in the information in the nic
368 * The list of probe addresses defined in skel_isa_probe_addrs[] will
369 * be passed to skel_isa_probe_addr(). If skel_isa_probe_addr()
370 * returns true, a struct isa_device will be created with isa->ioaddr
371 * set to the working I/O address, and skel_isa_probe() will be
374 * There is a standard mechanism for overriding the probe address list
375 * using ISA_PROBE_ADDRS. Do not implement any custom code to
376 * override the probe address list.
378 **************************************************************************
380 static int skel_isa_probe_addr ( isa_probe_addr_t ioaddr __unused ) {
384 static int skel_isa_probe ( struct nic *nic, struct isa_device *isa ) {
386 isa_fill_nic ( nic, isa );
387 nic->irqno = 0; /* No standard way to get IRQ for ISA */
389 /* Test for physical presence of NIC */
392 DBG ( "Could not find NIC: my explanation\n" );
397 /* point to NIC specific routines */
398 nic->nic_op = &skel_operations;
402 static void skel_isa_disable ( struct nic *nic __unused,
403 struct isa_device *isa __unused ) {
404 /* Reset the card to its initial state, disable DMA and
409 static isa_probe_addr_t skel_isa_probe_addrs[] = {
415 ISA_DRIVER ( skel_isa_driver, skel_isa_probe_addrs, skel_isa_probe_addr,
416 ISA_VENDOR('S','K','L'), 0x0000 );
418 DRIVER ( "SKEL/ISA", nic_driver, isa_driver, skel_isa_driver,
419 skel_isa_probe, skel_isa_disable );
421 ISA_ROM ( "skel-isa", "Skeleton ISA Adapter" );