urf_usbgem.c revision 6716431ba7de213d5c318e58dc24c8a36da9b068
/*
* urf_usbgem.c : Realtek RTL8150 USB to Fast Ethernet Driver for Solaris
*
* Copyright (c) 2003-2012 Masayuki Murayama. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
*
* 3. Neither the name of the author nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
* Changelog:
*/
/*
* TODO
*/
/* ======================================================= */
/*
* Solaris system header files and macros
*/
/* minimum kernel headers for drivers */
#include <sys/byteorder.h>
/* ethernet stuff */
#include <sys/ethernet.h>
/* interface card depend stuff */
#include "usbgem.h"
#include "usbgem_mii.h"
#include "rtl8150reg.h"
char ident[] = "rtl8150 usbnic driver v" VERSION;
/*
* Useful macros
*/
/*
* Debugging
*/
#ifdef DEBUG_LEVEL
static int urf_debug = DEBUG_LEVEL;
#else
#endif
/*
* Our configration for rtl8150
*/
/* timeouts */
/*
* Local device definitions
*/
struct chip_info {
int flags;
char *name;
int type;
};
struct urf_dev {
/*
* Misc HW information
*/
};
/*
* private functions
*/
/* mii operations */
/* nic operations */
static int urf_attach_chip(struct usbgem_dev *);
static int urf_reset_chip(struct usbgem_dev *);
static int urf_init_chip(struct usbgem_dev *);
static int urf_start_chip(struct usbgem_dev *);
static int urf_stop_chip(struct usbgem_dev *);
static int urf_set_media(struct usbgem_dev *);
static int urf_set_rx_filter(struct usbgem_dev *);
static int urf_get_stats(struct usbgem_dev *);
/* packet operations */
/* =============================================================== */
/*
* I/O functions
*/
/* =============================================================== */
/* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \
/* bRequest */ USB_REQ_SET_ADDRESS, \
/* wValue */ (p), \
/* wIndex */ 0, \
/* wLength */ 1, \
/* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \
/* bRequest */ USB_REQ_SET_ADDRESS, \
/* wValue */ (p), \
/* wIndex */ 0, \
/* wLength */ 2, \
/* BEGIN CSTYLED */
/* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV \
/* bRequest */ USB_REQ_SET_ADDRESS, \
/* wValue */ (p), \
/* wIndex */ 0, \
/* wLength */ (len), \
/* value */ (buf), \
/* END CSTYLED */
/* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST \
/* bRequest */ USB_REQ_SET_ADDRESS, \
/* wValue */ (p), \
/* wIndex */ 0, \
/* wLength */ sizeof ((*vp)), \
/* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST \
/* bRequest */ USB_REQ_SET_ADDRESS, \
/* wValue */ (p), \
/* wIndex */ 0, \
/* wLength */ (len), \
/* valuep */ (buf), \
/* =============================================================== */
/*
* variables
*/
/* =============================================================== */
static int urf_ppa = 0;
/* =============================================================== */
/*
* Hardware manupilation
*/
/* =============================================================== */
static int
{
int i;
int err;
for (i = 0; i < 100; i++) {
if ((reg & CR_SOFT_RST) == 0) {
return (USB_SUCCESS);
}
}
/* time out */
return (USB_FAILURE);
return (USB_FAILURE);
}
/*
* Setup rtl8150
*/
static int
{
int i;
int err;
/* ID registers: set later by urf_set_rx_filter */
/* Multicast registers: set later by urf_set_rx_filter */
/* Command register : Enable Tx and Rx before writing TCR and RCR */
/* Transmit configration register : */
/* Receive configuration register : disable rx filter */
#ifdef notdef
/* Media status register */
#endif
/* Configuration register 0: no need to change */
return (USB_SUCCESS);
return (USB_FAILURE);
}
static int
{
/* do nothing */
return (USB_SUCCESS);
}
static int
{
return (urf_reset_chip(dp));
}
static int
{
/* do nothing */
return (USB_SUCCESS);
}
static uint_t
{
return (usbgem_ether_crc_be(addr));
}
static int
{
int i;
int err;
#ifdef notdef
/* disable rx filter before changing it. */
#else
/* receive all packets while we change rx filter */
#endif
}
| RCR_AD; /* accept physical match */
/* promiscious mode implies all multicast and all physical */
/* accept all multicast packets */
/*
* make hash table to select interresting
* multicast address only.
*/
uint_t h;
/* hash table is 64 = 2^6 bit width */
}
}
/* set mac address */
/* set multicast hash table */
/* need to set up multicast hash table */
}
#if DEBUG_LEVEL > 2
#endif
return (USB_SUCCESS);
return (USB_FAILURE);
}
static int
{
int err;
/* select duplex: do nothing */
/* select speed: do nothing */
/* flow control */
/* setup flow control */
switch (dp->flow_control) {
case FLOW_CONTROL_SYMMETRIC:
break;
case FLOW_CONTROL_TX_PAUSE:
break;
case FLOW_CONTROL_RX_PAUSE:
break;
case FLOW_CONTROL_NONE:
default:
break;
}
}
return (USB_SUCCESS);
return (USB_FAILURE);
}
/*
*/
static mblk_t *
{
/*
* re-allocate mp
*/
if ((len & 0x3f) == 0) {
/* workaround for buggy USB hba */
len++;
}
return (NULL);
}
/* copy contents of the buffer */
}
*bp++ = 0;
}
}
return (mp);
}
static void
{
int i;
}
}
static mblk_t *
{
uint8_t *p;
#ifdef DEBUG_LEVEL
if (urf_debug > 2) {
}
#endif
/* Too short */
return (NULL);
}
/* get Rx header which is placed at tail of the packet. */
/* check if error happen */
if ((rxhd & (RXHD_VALID)) == 0) {
}
return (NULL);
}
#ifdef notdef
/* check packet size */
/* too long */
return (NULL);
return (NULL);
}
#endif
/* remove tailing crc field */
return (mp);
}
/*
* MII Interfaces
*/
static uint16_t
{
int reg;
*errp = USB_SUCCESS;
switch (index) {
case MII_CONTROL:
break;
case MII_STATUS:
break;
case MII_AN_ADVERT:
break;
case MII_AN_LPABLE:
break;
case MII_AN_EXPANSION:
break;
default:
return (0);
}
if (index == MII_STATUS) {
/*
* Fix MII status register as it does't have LINKUP and
* MFPRMBLSUPR bits.
*/
val &= ~MII_STATUS_LINKUP;
}
}
return (val);
return (0);
}
static void
{
int reg;
*errp = USB_SUCCESS;
switch (index) {
case MII_CONTROL:
break;
case MII_STATUS:
break;
case MII_AN_ADVERT:
break;
case MII_AN_LPABLE:
break;
case MII_AN_EXPANSION:
break;
default:
return;
}
;
}
/* ======================================================== */
/*
* OS depend (device driver DKI) routine
*/
/* ======================================================== */
static void
{
int i;
int err;
}
;
}
static int
{
int i;
int err;
/*
* setup flow control bit in eeprom
*/
/* enable PAUSE bit */
} else {
/* clear PAUSE bit */
}
/* make eeprom writable */
/* eerom allows only word access for writing */
/* make eeprom non-writable */
}
/*
* load EEPROM contents into nic
*/
for (i = 0; i < 100; i++) {
if ((reg & CR_AUTOLOAD) == 0) {
goto autoload_done;
}
}
/* timeout */
goto usberr;
/*
* mac address in EEPROM has loaded to ID registers.
*/
/* no need to scan phy */
#if DEBUG_LEVEL > 2
#endif
#ifdef CONFIG_VLAN
#endif
return (USB_SUCCESS);
return (USB_FAILURE);
}
static int
{
int i;
int ret;
int unit;
struct chip_info *p;
const char *drv_name;
struct usbgem_dev *dp;
void *base;
struct usbgem_conf *ugcp;
if (cmd == DDI_ATTACH) {
/*
* Check if the chip is supported.
*/
/*
* Check the chip if it is really realtek rtl8150
*/
/*
* construct usbgem configration
*/
/* name */
#ifdef USBGEM_CONFIG_GLDv3
#else
#endif
ugcp->usbgc_ifnum = 0;
/* the rx status partially replaces FCS */
ugcp->usbgc_rx_header_len = 0;
/* time out parameters */
/* flow control */
/* MII timeout parameters */
/* I/O methods */
/* mac operation */
#ifdef notdef
#else
#endif
/* packet operation */
/* mii operations */
/* mtu */
urf_ppa++;
return (DDI_SUCCESS);
}
err:
return (DDI_FAILURE);
}
if (cmd == DDI_RESUME) {
return (usbgem_resume(dip));
}
return (DDI_FAILURE);
}
static int
{
int ret;
if (cmd == DDI_DETACH) {
if (ret != DDI_SUCCESS) {
return (DDI_FAILURE);
}
urf_ppa--;
return (DDI_SUCCESS);
}
if (cmd == DDI_SUSPEND) {
return (usbgem_suspend(dip));
}
return (DDI_FAILURE);
}
/* ======================================================== */
/*
* OS depend (loadable streams driver) routine
*/
/* ======================================================== */
#ifdef USBGEM_CONFIG_GLDv3
#else
static struct module_info urfminfo = {
0, /* mi_idnum */
"urf", /* mi_idname */
0, /* mi_minpsz */
ETHERMTU, /* mi_maxpsz */
1, /* mi_lowat */
};
(int (*)()) NULL, /* qi_putp */
usbgem_rsrv, /* qi_srvp */
usbgem_open, /* qi_qopen */
usbgem_close, /* qi_qclose */
(int (*)()) NULL, /* qi_qadmin */
&urfminfo, /* qi_minfo */
NULL /* qi_mstat */
};
usbgem_wput, /* qi_putp */
usbgem_wsrv, /* qi_srvp */
(int (*)()) NULL, /* qi_qopen */
(int (*)()) NULL, /* qi_qclose */
(int (*)()) NULL, /* qi_qadmin */
&urfminfo, /* qi_minfo */
NULL /* qi_mstat */
};
&urfrinit, /* st_rdinit */
&urfwinit, /* st_wrinit */
NULL, /* st_muxrinit */
NULL /* st_muxwrinit */
};
static struct cb_ops cb_urf_ops = {
nulldev, /* cb_open */
nulldev, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
nodev, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
&urf_info, /* cb_stream */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
usbgem_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
urfattach, /* devo_attach */
urfdetach, /* devo_detach */
nodev, /* devo_reset */
&cb_urf_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
usbgem_power, /* devo_power */
#if DEVO_REV >= 4
usbgem_quiesce, /* devo_quiesce */
#endif
};
#endif
&mod_driverops, /* Type of module. This one is a driver */
ident,
&urf_ops, /* driver ops */
};
static struct modlinkage modlinkage = {
};
/* ======================================================== */
/*
* _init : done
*/
/* ======================================================== */
int
_init(void)
{
int status;
if (status != DDI_SUCCESS) {
return (status);
}
if (status != DDI_SUCCESS) {
}
return (status);
}
/*
* _fini : done
*/
int
_fini(void)
{
int status;
if (status == DDI_SUCCESS) {
}
return (status);
}
int
{
}