/** * gether_setup - initialize one ethernet-over-usb link * @g: gadget to associated with these links * @ethaddr: NULL, or a buffer in which the ethernet address of the * host side of the link is recorded * Context: may sleep * * This sets up the single network link that may be exported by a * gadget driver using this framework. The link layer addresses are * set up using module parameters. * * Returns negative errno, or zero on success */ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) { struct eth_dev *dev; struct net_device *net; int status; if (the_dev) return -EBUSY; net = alloc_etherdev(sizeof *dev); if (!net) return -ENOMEM; dev = netdev_priv(net); spin_lock_init(&dev->lock); spin_lock_init(&dev->req_lock); INIT_WORK(&dev->work, eth_work); INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->rx_reqs); /* network device setup */ dev->net = net; strcpy(net->name, "usb%d"); if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&g->dev, "using random %s ethernet address\n", "self"); if (get_ether_addr(host_addr, dev->host_mac)) dev_warn(&g->dev, "using random %s ethernet address\n", "host"); if (ethaddr) memcpy(ethaddr, dev->host_mac, ETH_ALEN); net->change_mtu = eth_change_mtu; net->hard_start_xmit = eth_start_xmit; net->open = eth_open; net->stop = eth_stop; /* watchdog_timeo, tx_timeout ... */ /* set_multicast_list */ SET_ETHTOOL_OPS(net, &ops); /* two kinds of host-initiated state changes: * - iff DATA transfer is active, carrier is "on" * - tx queueing enabled if open *and* carrier is "on" */ netif_stop_queue(net); netif_carrier_off(net); dev->gadget = g; SET_NETDEV_DEV(net, &g->dev); status = register_netdev(net); if (status < 0) { dev_dbg(&g->dev, "register_netdev failed, %d\n", status); free_netdev(net); } else { DECLARE_MAC_BUF(tmp); ETH_INFO(dev, "MAC %s\n", print_mac(tmp, net->dev_addr)); ETH_INFO(dev, "HOST MAC %s\n", print_mac(tmp, dev->host_mac)); the_dev = dev; } return status; }
static int eth_initialize(struct device *port) { struct eth_runtime *context = port->driver_data; struct eth_config *config = port->config->config_info; uint32_t base_addr; union { struct { uint8_t bytes[6]; uint8_t pad[2]; } __attribute__((packed)); uint32_t words[2]; } mac_addr; if (!eth_setup(port)) return -EPERM; base_addr = config->base_addr; /* Read the MAC address from the device. */ mac_addr.words[1] = eth_read(base_addr, REG_ADDR_MACADDR_HI); mac_addr.words[0] = eth_read(base_addr, REG_ADDR_MACADDR_LO); net_set_mac(mac_addr.bytes, sizeof(mac_addr.bytes)); /* Initialize transmit descriptor. */ context->tx_desc.tdes0 = 0; context->tx_desc.tdes1 = 0; context->tx_desc.buf1_ptr = (uint8_t *)context->tx_buf; context->tx_desc.tx_end_of_ring = 1; context->tx_desc.first_seg_in_frm = 1; context->tx_desc.last_seg_in_frm = 1; context->tx_desc.tx_end_of_ring = 1; /* Initialize receive descriptor. */ context->rx_desc.rdes0 = 0; context->rx_desc.rdes1 = 0; context->rx_desc.buf1_ptr = (uint8_t *)context->rx_buf; context->rx_desc.own = 1; context->rx_desc.first_desc = 1; context->rx_desc.last_desc = 1; context->rx_desc.rx_buf1_sz = UIP_BUFSIZE; context->rx_desc.rx_end_of_ring = 1; /* Install transmit and receive descriptors. */ eth_write(base_addr, REG_ADDR_RX_DESC_LIST, (uint32_t)&context->rx_desc); eth_write(base_addr, REG_ADDR_TX_DESC_LIST, (uint32_t)&context->tx_desc); eth_write(base_addr, REG_ADDR_MAC_CONF, /* Set the RMII speed to 100Mbps */ MAC_CONF_14_RMII_100M | /* Enable full-duplex mode */ MAC_CONF_11_DUPLEX | /* Enable transmitter */ MAC_CONF_3_TX_EN | /* Enable receiver */ MAC_CONF_2_RX_EN); eth_write(base_addr, REG_ADDR_INT_ENABLE, INT_ENABLE_NORMAL | /* Enable receive interrupts */ INT_ENABLE_RX); eth_write(base_addr, REG_ADDR_DMA_OPERATION, /* Enable receive store-and-forward mode for simplicity. */ OP_MODE_25_RX_STORE_N_FORWARD | /* Enable transmit store-and-forward mode for simplicity. */ OP_MODE_21_TX_STORE_N_FORWARD | /* Place the transmitter state machine in the Running state. */ OP_MODE_13_START_TX | /* Place the receiver state machine in the Running state. */ OP_MODE_1_START_RX); ETH_INFO("Enabled 100M full-duplex mode.\n"); net_driver_ethernet_register_tx(eth_net_tx); config->config_func(port); return 0; }