diff --git a/src/drivers/net/dm96xx.c b/src/drivers/net/dm96xx.c new file mode 100644 index 00000000..71d008fa --- /dev/null +++ b/src/drivers/net/dm96xx.c @@ -0,0 +1,667 @@ +/* + * Copyright (C) 2015 Michael Brown . + * + * 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include "dm96xx.h" + +/** @file + * + * Davicom DM96xx USB Ethernet driver + * + */ + +/****************************************************************************** + * + * Register operations + * + ****************************************************************************** + */ + +/** + * Reset device + * + * @v dm96xx DM96xx device + * @ret rc Return status code + */ +static int dm96xx_reset ( struct dm96xx_device *dm96xx ) { + int ncr; + int rc; + + /* Reset device */ + if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_NCR, + DM96XX_NCR_RST ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not reset: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + /* Wait for reset to complete */ + udelay ( DM96XX_RESET_DELAY_US ); + + /* Check that reset has completed */ + ncr = dm96xx_read_register ( dm96xx, DM96XX_NCR ); + if ( ncr < 0 ) { + rc = ncr; + DBGC ( dm96xx, "DM96XX %p failed to reset: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + if ( ncr & DM96XX_NCR_RST ) { + DBGC ( dm96xx, "DM96XX %p failed to reset (NCR=%#02x)\n", + dm96xx, ncr ); + return -EIO; + } + + return 0; +} + +/** + * Read MAC address + * + * @v dm96xx DM96xx device + * @v mac MAC address to fill in + * @ret rc Return status code + */ +static int dm96xx_read_mac ( struct dm96xx_device *dm96xx, uint8_t *mac ) { + int rc; + + /* Read MAC address */ + if ( ( rc = dm96xx_read_registers ( dm96xx, DM96XX_PAR, mac, + ETH_ALEN ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not read MAC address: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Write MAC address + * + * @v dm96xx DM96xx device + * @v mac MAC address + * @ret rc Return status code + */ +static int dm96xx_write_mac ( struct dm96xx_device *dm96xx, uint8_t *mac ) { + int rc; + + /* Write MAC address */ + if ( ( rc = dm96xx_write_registers ( dm96xx, DM96XX_PAR, mac, + ETH_ALEN ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not write MAC address: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Update link status based on network status register + * + * @v dm96xx DM96xx device + * @v nsr Network status register + */ +static void dm96xx_link_nsr ( struct dm96xx_device *dm96xx, unsigned int nsr ) { + struct net_device *netdev = dm96xx->netdev; + + if ( nsr & DM96XX_NSR_LINKST ) { + if ( ! netdev_link_ok ( netdev ) ) + netdev_link_up ( netdev ); + } else { + if ( netdev_link_ok ( netdev ) ) + netdev_link_down ( netdev ); + } +} + +/** + * Get link status + * + * @v dm96xx DM96xx device + * @ret rc Return status code + */ +static int dm96xx_check_link ( struct dm96xx_device *dm96xx ) { + int nsr; + int rc; + + /* Read network status register */ + nsr = dm96xx_read_register ( dm96xx, DM96XX_NSR ); + if ( nsr < 0 ) { + rc = nsr; + DBGC ( dm96xx, "DM96XX %p could not read network status: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + /* Update link status */ + dm96xx_link_nsr ( dm96xx, nsr ); + + return 0; +} + +/** + * Set DM9601-compatible RX header mode + * + * @v dm96xx DM96xx device + * @ret rc Return status code + */ +static int dm96xx_rx_mode ( struct dm96xx_device *dm96xx ) { + int chipr; + int mode_ctl; + int rc; + + /* Get chip revision */ + chipr = dm96xx_read_register ( dm96xx, DM96XX_CHIPR ); + if ( chipr < 0 ) { + rc = chipr; + DBGC ( dm96xx, "DM96XX %p could not read chip revision: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + /* Do nothing if device is a DM9601 anyway */ + if ( chipr == DM96XX_CHIPR_9601 ) + return 0; + + /* Read current mode control */ + mode_ctl = dm96xx_read_register ( dm96xx, DM96XX_MODE_CTL ); + if ( mode_ctl < 0 ) { + rc = mode_ctl; + DBGC ( dm96xx, "DM96XX %p could not read mode control: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + /* Write mode control */ + mode_ctl &= ~DM96XX_MODE_CTL_MODE; + if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_MODE_CTL, + mode_ctl ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not write mode control: %s\n", + dm96xx, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/****************************************************************************** + * + * Endpoint operations + * + ****************************************************************************** + */ + +/** + * Complete interrupt transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void dm96xx_intr_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, + usbnet.intr ); + struct net_device *netdev = dm96xx->netdev; + struct dm96xx_interrupt *intr; + size_t len = iob_len ( iobuf ); + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) + goto done; + + /* Record USB errors against the network device */ + if ( rc != 0 ) { + DBGC ( dm96xx, "DM96XX %p interrupt failed: %s\n", + dm96xx, strerror ( rc ) ); + DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); + netdev_rx_err ( netdev, NULL, rc ); + goto done; + } + + /* Extract message header */ + if ( len < sizeof ( *intr ) ) { + DBGC ( dm96xx, "DM96XX %p underlength interrupt:\n", dm96xx ); + DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); + netdev_rx_err ( netdev, NULL, -EINVAL ); + goto done; + } + intr = iobuf->data; + + /* Update link status */ + dm96xx_link_nsr ( dm96xx, intr->nsr ); + + done: + /* Free I/O buffer */ + free_iob ( iobuf ); +} + +/** Interrupt endpoint operations */ +static struct usb_endpoint_driver_operations dm96xx_intr_operations = { + .complete = dm96xx_intr_complete, +}; + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void dm96xx_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, + usbnet.in ); + struct net_device *netdev = dm96xx->netdev; + struct dm96xx_rx_header *header; + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) { + free_iob ( iobuf ); + return; + } + + /* Record USB errors against the network device */ + if ( rc != 0 ) { + DBGC ( dm96xx, "DM96XX %p bulk IN failed: %s\n", + dm96xx, strerror ( rc ) ); + goto err; + } + + /* Sanity check */ + if ( iob_len ( iobuf ) < ( sizeof ( *header ) + 4 /* CRC */ ) ) { + DBGC ( dm96xx, "DM96XX %p underlength bulk IN\n", dm96xx ); + DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto err; + } + + /* Strip header and CRC */ + header = iobuf->data; + iob_pull ( iobuf, sizeof ( *header ) ); + iob_unput ( iobuf, 4 /* CRC */ ); + + /* Check status */ + if ( header->rsr & ~DM96XX_RSR_MF ) { + DBGC ( dm96xx, "DM96XX %p receive error %02x:\n", + dm96xx, header->rsr ); + DBGC_HDA ( dm96xx, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EIO; + goto err; + } + + /* Hand off to network stack */ + netdev_rx ( netdev, iob_disown ( iobuf ) ); + return; + + err: + /* Hand off to network stack */ + netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations dm96xx_in_operations = { + .complete = dm96xx_in_complete, +}; + +/** + * Transmit packet + * + * @v dm96xx DM96xx device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int dm96xx_out_transmit ( struct dm96xx_device *dm96xx, + struct io_buffer *iobuf ) { + struct dm96xx_tx_header *header; + size_t len = iob_len ( iobuf ); + int rc; + + /* Prepend header */ + if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 ) + return rc; + header = iob_push ( iobuf, sizeof ( *header ) ); + header->len = cpu_to_le16 ( len ); + + /* Enqueue I/O buffer */ + if ( ( rc = usb_stream ( &dm96xx->usbnet.out, iobuf, 0 ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void dm96xx_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct dm96xx_device *dm96xx = container_of ( ep, struct dm96xx_device, + usbnet.out ); + struct net_device *netdev = dm96xx->netdev; + + /* Report TX completion */ + netdev_tx_complete_err ( netdev, iobuf, rc ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations dm96xx_out_operations = { + .complete = dm96xx_out_complete, +}; + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int dm96xx_open ( struct net_device *netdev ) { + struct dm96xx_device *dm96xx = netdev->priv; + unsigned int rcr; + int rc; + + /* Set DM9601-compatible RX header mode */ + if ( ( rc = dm96xx_rx_mode ( dm96xx ) ) != 0 ) + goto err_rx_mode; + + /* Write MAC address */ + if ( ( rc = dm96xx_write_mac ( dm96xx, netdev->ll_addr ) ) != 0 ) + goto err_write_mac; + + /* Open USB network device */ + if ( ( rc = usbnet_open ( &dm96xx->usbnet ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not open: %s\n", + dm96xx, strerror ( rc ) ); + goto err_open; + } + + /* Set receive filters */ + rcr = ( DM96XX_RCR_ALL | DM96XX_RCR_RUNT | DM96XX_RCR_PRMSC | + DM96XX_RCR_RXEN ); + if ( ( rc = dm96xx_write_register ( dm96xx, DM96XX_RCR, rcr ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not write receive filters: " + "%s\n", dm96xx, strerror ( rc ) ); + goto err_write_rcr; + } + + /* Update link status */ + if ( ( rc = dm96xx_check_link ( dm96xx ) ) != 0 ) + goto err_check_link; + + return 0; + + err_check_link: + err_write_rcr: + usbnet_close ( &dm96xx->usbnet ); + err_open: + err_write_mac: + err_rx_mode: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void dm96xx_close ( struct net_device *netdev ) { + struct dm96xx_device *dm96xx = netdev->priv; + + /* Close USB network device */ + usbnet_close ( &dm96xx->usbnet ); + + /* Reset device */ + dm96xx_reset ( dm96xx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int dm96xx_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct dm96xx_device *dm96xx = netdev->priv; + int rc; + + /* Transmit packet */ + if ( ( rc = dm96xx_out_transmit ( dm96xx, iobuf ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void dm96xx_poll ( struct net_device *netdev ) { + struct dm96xx_device *dm96xx = netdev->priv; + int rc; + + /* Poll USB bus */ + usb_poll ( dm96xx->bus ); + + /* Refill endpoints */ + if ( ( rc = usbnet_refill ( &dm96xx->usbnet ) ) != 0 ) + netdev_rx_err ( netdev, NULL, rc ); +} + +/** DM96xx network device operations */ +static struct net_device_operations dm96xx_operations = { + .open = dm96xx_open, + .close = dm96xx_close, + .transmit = dm96xx_transmit, + .poll = dm96xx_poll, +}; + +/****************************************************************************** + * + * USB interface + * + ****************************************************************************** + */ + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int dm96xx_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct net_device *netdev; + struct dm96xx_device *dm96xx; + int rc; + + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *dm96xx ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &dm96xx_operations ); + netdev->dev = &func->dev; + dm96xx = netdev->priv; + memset ( dm96xx, 0, sizeof ( *dm96xx ) ); + dm96xx->usb = usb; + dm96xx->bus = usb->port->hub->bus; + dm96xx->netdev = netdev; + usbnet_init ( &dm96xx->usbnet, func, &dm96xx_intr_operations, + &dm96xx_in_operations, &dm96xx_out_operations ); + usb_refill_init ( &dm96xx->usbnet.intr, 0, DM96XX_INTR_MAX_FILL ); + usb_refill_init ( &dm96xx->usbnet.in, DM96XX_IN_MTU, + DM96XX_IN_MAX_FILL ); + DBGC ( dm96xx, "DM96XX %p on %s\n", dm96xx, func->name ); + + /* Describe USB network device */ + if ( ( rc = usbnet_describe ( &dm96xx->usbnet, config ) ) != 0 ) { + DBGC ( dm96xx, "DM96XX %p could not describe: %s\n", + dm96xx, strerror ( rc ) ); + goto err_describe; + } + + /* Reset device */ + if ( ( rc = dm96xx_reset ( dm96xx ) ) != 0 ) + goto err_reset; + + /* Read MAC address */ + if ( ( rc = dm96xx_read_mac ( dm96xx, netdev->hw_addr ) ) != 0 ) + goto err_read_mac; + + /* Get initial link status */ + if ( ( rc = dm96xx_check_link ( dm96xx ) ) != 0 ) + goto err_check_link; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + usb_func_set_drvdata ( func, netdev ); + return 0; + + unregister_netdev ( netdev ); + err_register: + err_check_link: + err_read_mac: + err_reset: + err_describe: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void dm96xx_remove ( struct usb_function *func ) { + struct net_device *netdev = usb_func_get_drvdata ( func ); + + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** DM96xx device IDs */ +static struct usb_device_id dm96xx_ids[] = { + { + .name = "dm9601-corega", + .vendor = 0x07aa, + .product = 0x9601, + }, + { + .name = "dm9601", + .vendor = 0x0a46, + .product = 0x9601, + }, + { + .name = "zt6688", + .vendor = 0x0a46, + .product = 0x6688, + }, + { + .name = "st268", + .vendor = 0x0a46, + .product = 0x0268, + }, + { + .name = "adm8515", + .vendor = 0x0a46, + .product = 0x8515, + }, + { + .name = "dm9601-hirose", + .vendor = 0x0a47, + .product = 0x9601, + }, + { + .name = "dm9601-8101", + .vendor = 0x0fe6, + .product = 0x8101, + }, + { + .name = "dm9601-9700", + .vendor = 0x0fe6, + .product = 0x9700, + }, + { + .name = "dm9000e", + .vendor = 0x0a46, + .product = 0x9000, + }, + { + .name = "dm9620", + .vendor = 0x0a46, + .product = 0x9620, + }, + { + .name = "dm9621A", + .vendor = 0x0a46, + .product = 0x9621, + }, + { + .name = "dm9622", + .vendor = 0x0a46, + .product = 0x9622, + }, + { + .name = "dm962Oa", + .vendor = 0x0a46, + .product = 0x0269, + }, + { + .name = "dm9621a", + .vendor = 0x0a46, + .product = 0x1269, + }, +}; + +/** Davicom DM96xx driver */ +struct usb_driver dm96xx_driver __usb_driver = { + .ids = dm96xx_ids, + .id_count = ( sizeof ( dm96xx_ids ) / sizeof ( dm96xx_ids[0] ) ), + .probe = dm96xx_probe, + .remove = dm96xx_remove, +}; diff --git a/src/drivers/net/dm96xx.h b/src/drivers/net/dm96xx.h new file mode 100644 index 00000000..7cd144d2 --- /dev/null +++ b/src/drivers/net/dm96xx.h @@ -0,0 +1,194 @@ +#ifndef _DM96XX_H +#define _DM96XX_H + +/** @file + * + * Davicom DM96xx USB Ethernet driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** Read register(s) */ +#define DM96XX_READ_REGISTER \ + ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x00 ) ) + +/** Write register(s) */ +#define DM96XX_WRITE_REGISTER \ + ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x01 ) ) + +/** Write single register */ +#define DM96XX_WRITE1_REGISTER \ + ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x03 ) ) + +/** Network control register */ +#define DM96XX_NCR 0x00 +#define DM96XX_NCR_RST 0x01 /**< Software reset */ + +/** Network status register */ +#define DM96XX_NSR 0x01 +#define DM96XX_NSR_LINKST 0x40 /**< Link status */ + +/** Receive control register */ +#define DM96XX_RCR 0x05 +#define DM96XX_RCR_ALL 0x08 /**< Pass all multicast */ +#define DM96XX_RCR_RUNT 0x04 /**< Pass runt packet */ +#define DM96XX_RCR_PRMSC 0x02 /**< Promiscuous mode */ +#define DM96XX_RCR_RXEN 0x01 /**< RX enable */ + +/** Receive status register */ +#define DM96XX_RSR 0x06 +#define DM96XX_RSR_MF 0x40 /**< Multicast frame */ + +/** PHY address registers */ +#define DM96XX_PAR 0x10 + +/** Chip revision register */ +#define DM96XX_CHIPR 0x2c +#define DM96XX_CHIPR_9601 0x00 /**< DM9601 */ +#define DM96XX_CHIPR_9620 0x01 /**< DM9620 */ + +/** RX header control/status register (DM9620+ only) */ +#define DM96XX_MODE_CTL 0x91 +#define DM96XX_MODE_CTL_MODE 0x80 /**< 4-byte header mode */ + +/** DM96xx interrupt data */ +struct dm96xx_interrupt { + /** Network status register */ + uint8_t nsr; + /** Transmit status registers */ + uint8_t tsr[2]; + /** Receive status register */ + uint8_t rsr; + /** Receive overflow counter register */ + uint8_t rocr; + /** Receive packet counter */ + uint8_t rxc; + /** Transmit packet counter */ + uint8_t txc; + /** General purpose register */ + uint8_t gpr; +} __attribute__ (( packed )); + +/** DM96xx receive header */ +struct dm96xx_rx_header { + /** Packet status */ + uint8_t rsr; + /** Packet length (excluding this header, including CRC) */ + uint16_t len; +} __attribute__ (( packed )); + +/** DM96xx transmit header */ +struct dm96xx_tx_header { + /** Packet length (excluding this header) */ + uint16_t len; +} __attribute__ (( packed )); + +/** A DM96xx network device */ +struct dm96xx_device { + /** USB device */ + struct usb_device *usb; + /** USB bus */ + struct usb_bus *bus; + /** Network device */ + struct net_device *netdev; + /** USB network device */ + struct usbnet_device usbnet; +}; + +/** + * Read registers + * + * @v dm96xx DM96xx device + * @v offset Register offset + * @v data Data buffer + * @v len Length of data + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +dm96xx_read_registers ( struct dm96xx_device *dm96xx, unsigned int offset, + void *data, size_t len ) { + + return usb_control ( dm96xx->usb, DM96XX_READ_REGISTER, 0, offset, + data, len ); +} + +/** + * Read register + * + * @v dm96xx DM96xx device + * @v offset Register offset + * @ret value Register value, or negative error + */ +static inline __attribute__ (( always_inline )) int +dm96xx_read_register ( struct dm96xx_device *dm96xx, unsigned int offset ) { + uint8_t value; + int rc; + + if ( ( rc = dm96xx_read_registers ( dm96xx, offset, &value, + sizeof ( value ) ) ) != 0 ) + return rc; + return value; +} + +/** + * Write registers + * + * @v dm96xx DM96xx device + * @v offset Register offset + * @v data Data buffer + * @v len Length of data + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +dm96xx_write_registers ( struct dm96xx_device *dm96xx, unsigned int offset, + void *data, size_t len ) { + + return usb_control ( dm96xx->usb, DM96XX_WRITE_REGISTER, 0, offset, + data, len ); +} + +/** + * Write register + * + * @v dm96xx DM96xx device + * @v offset Register offset + * @v value Register value + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +dm96xx_write_register ( struct dm96xx_device *dm96xx, unsigned int offset, + uint8_t value ) { + + return usb_control ( dm96xx->usb, DM96XX_WRITE1_REGISTER, value, + offset, NULL, 0 ); +} + +/** Reset delay (in microseconds) */ +#define DM96XX_RESET_DELAY_US 10 + +/** Interrupt maximum fill level + * + * This is a policy decision. + */ +#define DM96XX_INTR_MAX_FILL 2 + +/** Bulk IN maximum fill level + * + * This is a policy decision. + */ +#define DM96XX_IN_MAX_FILL 8 + +/** Bulk IN buffer size */ +#define DM96XX_IN_MTU \ + ( 4 /* DM96xx header */ + ETH_FRAME_LEN + \ + 4 /* possible VLAN header */ + 4 /* CRC */ ) + +#endif /* _DM96XX_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index a71a6035..a3b68327 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -164,7 +164,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_ecm ( ERRFILE_DRIVER | 0x006c0000 ) #define ERRFILE_ncm ( ERRFILE_DRIVER | 0x006d0000 ) #define ERRFILE_usbnet ( ERRFILE_DRIVER | 0x006e0000 ) - +#define ERRFILE_dm96xx ( ERRFILE_DRIVER | 0x006f0000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) #define ERRFILE_hermon ( ERRFILE_DRIVER | 0x00720000 ) diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index 5ea9fa4a..59661f70 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -78,6 +78,9 @@ struct usb_setup_packet { /** Class-specific request type */ #define USB_TYPE_CLASS ( 1 << 5 ) +/** Vendor-specific request type */ +#define USB_TYPE_VENDOR ( 2 << 5 ) + /** Request recipient is the device */ #define USB_RECIP_DEVICE ( 0 << 0 )