| /* | |
| * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of the | |
| * License, or (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, but | |
| * WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| * 02110-1301, USA. | |
| * | |
| * You can also choose to distribute this program under the terms of | |
| * the Unmodified Binary Distribution Licence (as given in the file | |
| * COPYING.UBDL), provided that you have satisfied its requirements. | |
| */ | |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <errno.h> | |
| #include <byteswap.h> | |
| #include <ipxe/netdevice.h> | |
| #include <ipxe/ethernet.h> | |
| #include <ipxe/if_ether.h> | |
| #include <ipxe/iobuf.h> | |
| #include <ipxe/malloc.h> | |
| #include <ipxe/pci.h> | |
| #include "skeleton.h" | |
| /** @file | |
| * | |
| * Skeleton network driver | |
| * | |
| */ | |
| /****************************************************************************** | |
| * | |
| * Device reset | |
| * | |
| ****************************************************************************** | |
| */ | |
| /** | |
| * Reset hardware | |
| * | |
| * @v skel Skeleton device | |
| * @ret rc Return status code | |
| */ | |
| static int skeleton_reset ( struct skeleton_nic *skel ) { | |
| DBGC ( skel, "SKELETON %p does not yet support reset\n", skel ); | |
| return -ENOTSUP; | |
| } | |
| /****************************************************************************** | |
| * | |
| * Link state | |
| * | |
| ****************************************************************************** | |
| */ | |
| /** | |
| * Check link state | |
| * | |
| * @v netdev Network device | |
| */ | |
| static void skeleton_check_link ( struct net_device *netdev ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| DBGC ( skel, "SKELETON %p does not yet support link state\n", skel ); | |
| netdev_link_err ( netdev, -ENOTSUP ); | |
| } | |
| /****************************************************************************** | |
| * | |
| * Network device interface | |
| * | |
| ****************************************************************************** | |
| */ | |
| /** | |
| * Open network device | |
| * | |
| * @v netdev Network device | |
| * @ret rc Return status code | |
| */ | |
| static int skeleton_open ( struct net_device *netdev ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| DBGC ( skel, "SKELETON %p does not yet support open\n", skel ); | |
| return -ENOTSUP; | |
| } | |
| /** | |
| * Close network device | |
| * | |
| * @v netdev Network device | |
| */ | |
| static void skeleton_close ( struct net_device *netdev ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| DBGC ( skel, "SKELETON %p does not yet support close\n", skel ); | |
| } | |
| /** | |
| * Transmit packet | |
| * | |
| * @v netdev Network device | |
| * @v iobuf I/O buffer | |
| * @ret rc Return status code | |
| */ | |
| static int skeleton_transmit ( struct net_device *netdev, | |
| struct io_buffer *iobuf ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| DBGC ( skel, "SKELETON %p does not yet support transmit\n", skel ); | |
| ( void ) iobuf; | |
| return -ENOTSUP; | |
| } | |
| /** | |
| * Poll for completed and received packets | |
| * | |
| * @v netdev Network device | |
| */ | |
| static void skeleton_poll ( struct net_device *netdev ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| /* Not yet implemented */ | |
| ( void ) skel; | |
| } | |
| /** | |
| * Enable or disable interrupts | |
| * | |
| * @v netdev Network device | |
| * @v enable Interrupts should be enabled | |
| */ | |
| static void skeleton_irq ( struct net_device *netdev, int enable ) { | |
| struct skeleton_nic *skel = netdev->priv; | |
| DBGC ( skel, "SKELETON %p does not yet support interrupts\n", skel ); | |
| ( void ) enable; | |
| } | |
| /** Skeleton network device operations */ | |
| static struct net_device_operations skeleton_operations = { | |
| .open = skeleton_open, | |
| .close = skeleton_close, | |
| .transmit = skeleton_transmit, | |
| .poll = skeleton_poll, | |
| .irq = skeleton_irq, | |
| }; | |
| /****************************************************************************** | |
| * | |
| * PCI interface | |
| * | |
| ****************************************************************************** | |
| */ | |
| /** | |
| * Probe PCI device | |
| * | |
| * @v pci PCI device | |
| * @ret rc Return status code | |
| */ | |
| static int skeleton_probe ( struct pci_device *pci ) { | |
| struct net_device *netdev; | |
| struct skeleton_nic *skel; | |
| int rc; | |
| /* Allocate and initialise net device */ | |
| netdev = alloc_etherdev ( sizeof ( *skel ) ); | |
| if ( ! netdev ) { | |
| rc = -ENOMEM; | |
| goto err_alloc; | |
| } | |
| netdev_init ( netdev, &skeleton_operations ); | |
| skel = netdev->priv; | |
| pci_set_drvdata ( pci, netdev ); | |
| netdev->dev = &pci->dev; | |
| memset ( skel, 0, sizeof ( *skel ) ); | |
| /* Fix up PCI device */ | |
| adjust_pci_device ( pci ); | |
| /* Map registers */ | |
| skel->regs = pci_ioremap ( pci, pci->membase, SKELETON_BAR_SIZE ); | |
| if ( ! skel->regs ) { | |
| rc = -ENODEV; | |
| goto err_ioremap; | |
| } | |
| /* Reset the NIC */ | |
| if ( ( rc = skeleton_reset ( skel ) ) != 0 ) | |
| goto err_reset; | |
| /* Register network device */ | |
| if ( ( rc = register_netdev ( netdev ) ) != 0 ) | |
| goto err_register_netdev; | |
| /* Set initial link state */ | |
| skeleton_check_link ( netdev ); | |
| return 0; | |
| unregister_netdev ( netdev ); | |
| err_register_netdev: | |
| skeleton_reset ( skel ); | |
| err_reset: | |
| iounmap ( skel->regs ); | |
| err_ioremap: | |
| netdev_nullify ( netdev ); | |
| netdev_put ( netdev ); | |
| err_alloc: | |
| return rc; | |
| } | |
| /** | |
| * Remove PCI device | |
| * | |
| * @v pci PCI device | |
| */ | |
| static void skeleton_remove ( struct pci_device *pci ) { | |
| struct net_device *netdev = pci_get_drvdata ( pci ); | |
| struct skeleton_nic *skel = netdev->priv; | |
| /* Unregister network device */ | |
| unregister_netdev ( netdev ); | |
| /* Reset card */ | |
| skeleton_reset ( skel ); | |
| /* Free network device */ | |
| iounmap ( skel->regs ); | |
| netdev_nullify ( netdev ); | |
| netdev_put ( netdev ); | |
| } | |
| /** Skeleton PCI device IDs */ | |
| static struct pci_device_id skeleton_nics[] = { | |
| PCI_ROM ( 0x5ce1, 0x5ce1, "skel", "Skeleton", 0 ), | |
| }; | |
| /** Skeleton PCI driver */ | |
| struct pci_driver skeleton_driver __pci_driver = { | |
| .ids = skeleton_nics, | |
| .id_count = ( sizeof ( skeleton_nics ) / sizeof ( skeleton_nics[0] ) ), | |
| .probe = skeleton_probe, | |
| .remove = skeleton_remove, | |
| }; |