Changeset View
Standalone View
sys/dev/usb/net/if_cdce.c
Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
static uether_fn_t cdce_attach_post; | static uether_fn_t cdce_attach_post; | ||||
static uether_fn_t cdce_init; | static uether_fn_t cdce_init; | ||||
static uether_fn_t cdce_stop; | static uether_fn_t cdce_stop; | ||||
static uether_fn_t cdce_start; | static uether_fn_t cdce_start; | ||||
static uether_fn_t cdce_setmulti; | static uether_fn_t cdce_setmulti; | ||||
static uether_fn_t cdce_setpromisc; | static uether_fn_t cdce_setpromisc; | ||||
static int cdce_attach_post_sub(struct usb_ether *); | |||||
static int cdce_ioctl(struct ifnet *, u_long, caddr_t); | |||||
static int cdce_media_change_cb(struct ifnet *); | |||||
static void cdce_media_status_cb(struct ifnet *, struct ifmediareq *); | |||||
static uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); | static uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); | ||||
#ifdef USB_DEBUG | #ifdef USB_DEBUG | ||||
static int cdce_debug = 0; | static int cdce_debug = 0; | ||||
static int cdce_tx_interval = 0; | static int cdce_tx_interval = 0; | ||||
static SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | static SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | |||||
MODULE_DEPEND(cdce, usb, 1, 1, 1); | MODULE_DEPEND(cdce, usb, 1, 1, 1); | ||||
MODULE_DEPEND(cdce, ether, 1, 1, 1); | MODULE_DEPEND(cdce, ether, 1, 1, 1); | ||||
USB_PNP_DEVICE_INFO(cdce_switch_devs); | USB_PNP_DEVICE_INFO(cdce_switch_devs); | ||||
USB_PNP_HOST_INFO(cdce_host_devs); | USB_PNP_HOST_INFO(cdce_host_devs); | ||||
USB_PNP_DUAL_INFO(cdce_dual_devs); | USB_PNP_DUAL_INFO(cdce_dual_devs); | ||||
static const struct usb_ether_methods cdce_ue_methods = { | static const struct usb_ether_methods cdce_ue_methods = { | ||||
.ue_attach_post = cdce_attach_post, | .ue_attach_post = cdce_attach_post, | ||||
.ue_attach_post_sub = cdce_attach_post_sub, | |||||
.ue_start = cdce_start, | .ue_start = cdce_start, | ||||
.ue_init = cdce_init, | .ue_init = cdce_init, | ||||
.ue_stop = cdce_stop, | .ue_stop = cdce_stop, | ||||
.ue_setmulti = cdce_setmulti, | .ue_setmulti = cdce_setmulti, | ||||
.ue_setpromisc = cdce_setpromisc, | .ue_setpromisc = cdce_setpromisc, | ||||
}; | }; | ||||
#if CDCE_HAVE_NCM | #if CDCE_HAVE_NCM | ||||
▲ Show 20 Lines • Show All 238 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
cdce_attach_post(struct usb_ether *ue) | cdce_attach_post(struct usb_ether *ue) | ||||
{ | { | ||||
/* no-op */ | /* no-op */ | ||||
return; | return; | ||||
} | } | ||||
static int | static int | ||||
cdce_attach_post_sub(struct usb_ether *ue) | |||||
{ | |||||
struct cdce_softc *sc = uether_getsc(ue); | |||||
struct ifnet *ifp = uether_getifp(ue); | |||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
ifp->if_start = uether_start; | |||||
ifp->if_ioctl = cdce_ioctl; | |||||
ifp->if_init = uether_init; | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); | |||||
ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; | |||||
IFQ_SET_READY(&ifp->if_snd); | |||||
if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0); | |||||
if_setcapenable(ifp, if_getcapabilities(ifp)); | |||||
ifmedia_init(&sc->sc_media, IFM_IMASK, cdce_media_change_cb, | |||||
cdce_media_status_cb); | |||||
ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); | |||||
ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); | |||||
sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media; | |||||
return 0; | |||||
} | |||||
static int | |||||
cdce_attach(device_t dev) | cdce_attach(device_t dev) | ||||
{ | { | ||||
struct cdce_softc *sc = device_get_softc(dev); | struct cdce_softc *sc = device_get_softc(dev); | ||||
struct usb_ether *ue = &sc->sc_ue; | struct usb_ether *ue = &sc->sc_ue; | ||||
struct usb_attach_arg *uaa = device_get_ivars(dev); | struct usb_attach_arg *uaa = device_get_ivars(dev); | ||||
struct usb_interface *iface; | struct usb_interface *iface; | ||||
const struct usb_cdc_union_descriptor *ud; | const struct usb_cdc_union_descriptor *ud; | ||||
const struct usb_interface_descriptor *id; | const struct usb_interface_descriptor *id; | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | cdce_detach(device_t dev) | ||||
struct cdce_softc *sc = device_get_softc(dev); | struct cdce_softc *sc = device_get_softc(dev); | ||||
struct usb_ether *ue = &sc->sc_ue; | struct usb_ether *ue = &sc->sc_ue; | ||||
/* stop all USB transfers first */ | /* stop all USB transfers first */ | ||||
usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); | usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); | ||||
uether_ifdetach(ue); | uether_ifdetach(ue); | ||||
mtx_destroy(&sc->sc_mtx); | mtx_destroy(&sc->sc_mtx); | ||||
ifmedia_removeall(&sc->sc_media); | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
cdce_start(struct usb_ether *ue) | cdce_start(struct usb_ether *ue) | ||||
{ | { | ||||
struct cdce_softc *sc = uether_getsc(ue); | struct cdce_softc *sc = uether_getsc(ue); | ||||
/* | /* | ||||
* Start the USB transfers, if not already started: | * Start the USB transfers, if not already started: | ||||
*/ | */ | ||||
usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]); | usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]); | ||||
usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]); | usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]); | ||||
} | } | ||||
static int | |||||
cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) | |||||
{ | |||||
struct usb_ether *ue = ifp->if_softc; | |||||
struct cdce_softc *sc = uether_getsc(ue); | |||||
struct ifreq *ifr = (struct ifreq *)data; | |||||
int error; | |||||
error = 0; | |||||
hselasky: no need to set error = 0, when error is set in all cases below. | |||||
jmgAuthorUnsubmitted Done Inline ActionsCombo of copying what other _ioctl's routines do (if_ure) and not noticing this. I'd prefer to keep it, to match a few others. Appears we have three different styles in the various network drivers, one is this, if cases, and direct return of value. If I remove it, it'd deviate and create a new pattern. If someone wants to standardize how the _ioctl functions run, they are free to do it here. jmg: Combo of copying what other _ioctl's routines do (if_ure) and not noticing this. I'd prefer to… | |||||
emasteUnsubmitted Done Inline ActionsPersonally I'd like to adopt early-return in style(9) but that's certainly a bigger discussion than this driver. emaste: Personally I'd like to adopt early-return in style(9) but that's certainly a bigger discussion… | |||||
hselaskyUnsubmitted Done Inline ActionsAs long as the compiler doesn't complain. hselasky: As long as the compiler doesn't complain. | |||||
jmgAuthorUnsubmitted Done Inline Actions
yeah, doesn't seem to generate any warnings/errors. jmg: > As long as the compiler doesn't complain.
yeah, doesn't seem to generate any warnings/errors. | |||||
switch(command) { | |||||
case SIOCGIFMEDIA: | |||||
case SIOCSIFMEDIA: | |||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); | |||||
break; | |||||
default: | |||||
error = uether_ioctl(ifp, command, data); | |||||
break; | |||||
} | |||||
return (error); | |||||
} | |||||
static void | static void | ||||
cdce_free_queue(struct mbuf **ppm, uint8_t n) | cdce_free_queue(struct mbuf **ppm, uint8_t n) | ||||
{ | { | ||||
uint8_t x; | uint8_t x; | ||||
for (x = 0; x != n; x++) { | for (x = 0; x != n; x++) { | ||||
if (ppm[x] != NULL) { | if (ppm[x] != NULL) { | ||||
m_freem(ppm[x]); | m_freem(ppm[x]); | ||||
ppm[x] = NULL; | ppm[x] = NULL; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static int | |||||
cdce_media_change_cb(struct ifnet *ifp) | |||||
{ | |||||
return (EOPNOTSUPP); | |||||
} | |||||
static void | static void | ||||
cdce_media_status_cb(struct ifnet *ifp, struct ifmediareq *ifmr) | |||||
{ | |||||
if ((if_getflags(ifp) & IFF_UP) == 0) | |||||
return; | |||||
ifmr->ifm_active = IFM_ETHER; | |||||
ifmr->ifm_status = IFM_AVALID; | |||||
ifmr->ifm_status |= | |||||
ifp->if_link_state == LINK_STATE_UP ? IFM_ACTIVE : 0; | |||||
} | |||||
static void | |||||
cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) | cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct cdce_softc *sc = usbd_xfer_softc(xfer); | struct cdce_softc *sc = usbd_xfer_softc(xfer); | ||||
struct ifnet *ifp = uether_getifp(&sc->sc_ue); | struct ifnet *ifp = uether_getifp(&sc->sc_ue); | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct mbuf *mt; | struct mbuf *mt; | ||||
uint32_t crc; | uint32_t crc; | ||||
uint8_t x; | uint8_t x; | ||||
▲ Show 20 Lines • Show All 257 Lines • ▼ Show 20 Lines | tr_stall: | ||||
cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); | cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) | cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) | ||||
{ | { | ||||
struct cdce_softc *sc = usbd_xfer_softc(xfer); | u_char buf[128]; | ||||
hselaskyUnsubmitted Done Inline ActionsIf you use: buf[CDCE_IND_SIZE_MAX] The MIN() check below won't be needed. --HPS hselasky: If you use:
buf[CDCE_IND_SIZE_MAX]
The MIN() check below won't be needed.
--HPS | |||||
jmgAuthorUnsubmitted Done Inline ActionsDo you know where this constant came from? I can't find it in the CDC spec. I GUESS if all three messages specified by the spec were sent and sent only once, that would add up to 32, BUT this prevents future other messages from being sent (I didn't check a newer version of the CDCE spec). Hmm.. I'm split on this. the max size for the function is a bit divorced and so not immediately clear, and I'm more inclined to write defensively, especially when small checks like these will not significantly impact performance (re MIN usage). jmg: Do you know where this constant came from? I can't find it in the CDC spec. I GUESS if all… | |||||
hselaskyUnsubmitted Done Inline ActionsThis is just a software value. I think USB does not define this size. hselasky: This is just a software value. I think USB does not define this size. | |||||
jmgAuthorUnsubmitted Done Inline Actions
ok, yeah, that's what I thought. I have a feeling this might need to be increased if we start sending commands and getting data back from it, which may be necessary if we want to do additional things w/ it. jmg: > This is just a software value. I think USB does not define this size.
ok, yeah, that's what… | |||||
int actlen; | struct usb_cdc_notification ucn; | ||||
struct cdce_softc *sc; | |||||
struct ifnet *ifp; | |||||
struct usb_page_cache *pc; | |||||
int off, actlen; | |||||
uint32_t downrate, uprate; | |||||
sc = usbd_xfer_softc(xfer); | |||||
ifp = uether_getifp(&sc->sc_ue); | |||||
pc = usbd_xfer_get_frame(xfer, 0); | |||||
Done Inline ActionsI have a feeling buf should be under #ifdef USB_DEBUG hselasky: I have a feeling buf should be under
```
#ifdef USB_DEBUG
``` | |||||
Done Inline Actions
yes, it was. I did an #else and defined cdce_debug to 0 instead of putting ifdef in the body of the code. IMO, having the compiler eliminate the dead code makes the code easier to read than adding a bunch of ifdef's (one to define the var buf, and a second for the actual code. jmg: > I have a feeling buf should be under
>
> ```
> #ifdef USB_DEBUG
> ```
yes, it was. I did… | |||||
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); | ||||
switch (USB_GET_STATE(xfer)) { | switch (USB_GET_STATE(xfer)) { | ||||
case USB_ST_TRANSFERRED: | case USB_ST_TRANSFERRED: | ||||
if (USB_DEBUG_VAR) | |||||
Done Inline ActionsDitto. hselasky: Ditto. | |||||
usbd_copy_out(pc, 0, buf, MIN(actlen, sizeof buf)); | |||||
emasteUnsubmitted Done Inline Actionsis actlen > sizeof buf ever expected to happen? emaste: is actlen > sizeof buf ever expected to happen? | |||||
jmgAuthorUnsubmitted Done Inline Actionsper previous, I don't know, and prefer not to assume things that could end up causing buffer overruns. jmg: per previous, I don't know, and prefer not to assume things that could end up causing buffer… | |||||
emasteUnsubmitted Done Inline ActionsYes, definitely do not want a buffer overrun due to an assumption. But, I mean should we emit an error? Should we discard the buffer rather than processing part of it? emaste: Yes, definitely do not want a buffer overrun due to an assumption. But, I mean should we emit… | |||||
jmgAuthorUnsubmitted Done Inline ActionsI think you're missing that this is a debug statement. The user should know/understand when the bytes is larger than the output. jmg: I think you're missing that this is a debug statement. The user should know/understand when… | |||||
emasteUnsubmitted Done Inline ActionsAh, indeed. I noticed the DPRINTF but missed the USB_DEBUG_VAR above somehow emaste: Ah, indeed. I noticed the DPRINTF but missed the USB_DEBUG_VAR above somehow | |||||
DPRINTF("Received %d bytes: %*D\n", actlen, | |||||
(int)MIN(actlen, sizeof buf), buf, ""); | |||||
DPRINTF("Received %d bytes\n", actlen); | off = 0; | ||||
while (actlen - off >= UCDC_NOTIFICATION_LENGTH) { | |||||
usbd_copy_out(pc, off, &ucn, UCDC_NOTIFICATION_LENGTH); | |||||
/* TODO: decode some indications */ | do { | ||||
if (ucn.bmRequestType != 0xa1) | |||||
break; | |||||
switch (ucn.bNotification) { | |||||
case UCDC_N_NETWORK_CONNECTION: | |||||
DPRINTF("changing link state: %d\n", | |||||
UGETW(ucn.wValue)); | |||||
if_link_state_change(ifp, | |||||
UGETW(ucn.wValue) ? LINK_STATE_UP : | |||||
LINK_STATE_DOWN); | |||||
break; | |||||
case UCDC_N_CONNECTION_SPEED_CHANGE: | |||||
if (UGETW(ucn.wLength) != 8) | |||||
break; | |||||
usbd_copy_out(pc, off + | |||||
UCDC_NOTIFICATION_LENGTH, | |||||
&ucn.data, UGETW(ucn.wLength)); | |||||
downrate = UGETDW(ucn.data); | |||||
uprate = UGETDW(ucn.data); | |||||
if (downrate != uprate) | |||||
break; | |||||
/* set rate */ | |||||
DPRINTF("changing baudrate: %u\n", | |||||
downrate); | |||||
if_setbaudrate(ifp, downrate); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} while (0); | |||||
off += UCDC_NOTIFICATION_LENGTH + UGETW(ucn.wLength); | |||||
} | |||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case USB_ST_SETUP: | case USB_ST_SETUP: | ||||
tr_setup: | tr_setup: | ||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); | ||||
usbd_transfer_submit(xfer); | usbd_transfer_submit(xfer); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 510 Lines • Show Last 20 Lines |
no need to set error = 0, when error is set in all cases below.