mirror of https://github.com/ipxe/ipxe.git
[ncm] Use generic refill framework for bulk IN and interrupt endpoints
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/34/head
parent
1706ab7ff3
commit
14fc311271
|
@ -35,10 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
*
|
||||
*/
|
||||
|
||||
/** Ring refill profiler */
|
||||
static struct profiler ncm_refill_profiler __profiler =
|
||||
{ .name = "ncm.refill" };
|
||||
|
||||
/** Interrupt completion profiler */
|
||||
static struct profiler ncm_intr_profiler __profiler =
|
||||
{ .name = "ncm.intr" };
|
||||
|
@ -55,144 +51,6 @@ static struct profiler ncm_in_datagram_profiler __profiler =
|
|||
static struct profiler ncm_out_profiler __profiler =
|
||||
{ .name = "ncm.out" };
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Ring management
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Transcribe receive ring name (for debugging)
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @v ring Receive ring
|
||||
* @ret name Receive ring name
|
||||
*/
|
||||
static inline const char * ncm_rx_name ( struct ncm_device *ncm,
|
||||
struct ncm_rx_ring *ring ) {
|
||||
if ( ring == &ncm->intr ) {
|
||||
return "interrupt";
|
||||
} else if ( ring == &ncm->in ) {
|
||||
return "bulk IN";
|
||||
} else {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate receive ring buffers
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @v ring Receive ring
|
||||
* @v mtu I/O buffer size
|
||||
* @v count Number of I/O buffers
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ncm_rx_alloc ( struct ncm_device *ncm, struct ncm_rx_ring *ring,
|
||||
size_t mtu, unsigned int count ) {
|
||||
struct io_buffer *iobuf;
|
||||
struct io_buffer *tmp;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Initialise ring */
|
||||
ring->mtu = mtu;
|
||||
INIT_LIST_HEAD ( &ring->list );
|
||||
|
||||
/* Allocate I/O buffers */
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
iobuf = alloc_iob ( mtu );
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( ncm, "NCM %p could not allocate %dx %zd-byte "
|
||||
"buffers for %s\n", ncm, count, mtu,
|
||||
ncm_rx_name ( ncm, ring ) );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
list_add ( &iobuf->list, &ring->list );
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_alloc:
|
||||
list_for_each_entry_safe ( iobuf, tmp, &ring->list, list ) {
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refill receive ring
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @v ring Receive ring
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ncm_rx_refill ( struct ncm_device *ncm, struct ncm_rx_ring *ring ) {
|
||||
struct io_buffer *iobuf;
|
||||
int rc;
|
||||
|
||||
/* Enqueue any recycled I/O buffers */
|
||||
while ( ( iobuf = list_first_entry ( &ring->list, struct io_buffer,
|
||||
list ) ) ) {
|
||||
|
||||
/* Profile refill */
|
||||
profile_start ( &ncm_refill_profiler );
|
||||
|
||||
/* Reset size */
|
||||
iob_put ( iobuf, ( ring->mtu - iob_len ( iobuf ) ) );
|
||||
|
||||
/* Enqueue I/O buffer */
|
||||
if ( ( rc = usb_stream ( &ring->ep, iobuf, 0 ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not enqueue %s: %s\n", ncm,
|
||||
ncm_rx_name ( ncm, ring ), strerror ( rc ) );
|
||||
/* Leave in recycled list and wait for next refill */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Remove from recycled list */
|
||||
list_del ( &iobuf->list );
|
||||
profile_stop ( &ncm_refill_profiler );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recycle receive buffer
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @v ring Receive ring
|
||||
* @v iobuf I/O buffer
|
||||
*/
|
||||
static inline void ncm_rx_recycle ( struct ncm_device *ncm __unused,
|
||||
struct ncm_rx_ring *ring,
|
||||
struct io_buffer *iobuf ) {
|
||||
|
||||
/* Add to recycled list */
|
||||
list_add_tail ( &iobuf->list, &ring->list );
|
||||
}
|
||||
|
||||
/**
|
||||
* Free receive ring
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @v ring Receive ring
|
||||
*/
|
||||
static void ncm_rx_free ( struct ncm_device *ncm __unused,
|
||||
struct ncm_rx_ring *ring ) {
|
||||
struct io_buffer *iobuf;
|
||||
struct io_buffer *tmp;
|
||||
|
||||
/* Free I/O buffers */
|
||||
list_for_each_entry_safe ( iobuf, tmp, &ring->list, list ) {
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* CDC-NCM communications interface
|
||||
|
@ -209,7 +67,7 @@ static void ncm_rx_free ( struct ncm_device *ncm __unused,
|
|||
*/
|
||||
static void ncm_intr_complete ( struct usb_endpoint *ep,
|
||||
struct io_buffer *iobuf, int rc ) {
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, intr.ep);
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, intr );
|
||||
struct net_device *netdev = ncm->netdev;
|
||||
struct usb_setup_packet *message;
|
||||
size_t len = iob_len ( iobuf );
|
||||
|
@ -219,21 +77,22 @@ static void ncm_intr_complete ( struct usb_endpoint *ep,
|
|||
|
||||
/* Ignore packets cancelled when the endpoint closes */
|
||||
if ( ! ep->open )
|
||||
goto done;
|
||||
goto ignore;
|
||||
|
||||
/* Ignore packets with errors */
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( ncm, "NCM %p interrupt failed: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
|
||||
goto done;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Extract message header */
|
||||
if ( len < sizeof ( *message ) ) {
|
||||
DBGC ( ncm, "NCM %p underlength interrupt:\n", ncm );
|
||||
DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
|
||||
goto done;
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
message = iobuf->data;
|
||||
|
||||
|
@ -257,13 +116,20 @@ static void ncm_intr_complete ( struct usb_endpoint *ep,
|
|||
default:
|
||||
DBGC ( ncm, "NCM %p unrecognised interrupt:\n", ncm );
|
||||
DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
|
||||
break;
|
||||
goto error;
|
||||
}
|
||||
|
||||
done:
|
||||
/* Recycle buffer */
|
||||
ncm_rx_recycle ( ncm, &ncm->intr, iobuf );
|
||||
/* Free I/O buffer */
|
||||
free_iob ( iobuf );
|
||||
profile_stop ( &ncm_intr_profiler );
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
|
||||
ignore:
|
||||
free_iob ( iobuf );
|
||||
return;
|
||||
}
|
||||
|
||||
/** Interrupt endpoint operations */
|
||||
|
@ -280,27 +146,20 @@ static struct usb_endpoint_driver_operations ncm_intr_operations = {
|
|||
static int ncm_comms_open ( struct ncm_device *ncm ) {
|
||||
int rc;
|
||||
|
||||
/* Allocate I/O buffers */
|
||||
if ( ( rc = ncm_rx_alloc ( ncm, &ncm->intr, ncm->intr.ep.mtu,
|
||||
NCM_INTR_COUNT ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not allocate RX buffers: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Open interrupt endpoint */
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->intr.ep ) ) != 0 ) {
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->intr ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not open interrupt: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_open;
|
||||
}
|
||||
|
||||
/* Refill interrupt endpoint */
|
||||
usb_refill ( &ncm->intr );
|
||||
|
||||
return 0;
|
||||
|
||||
usb_endpoint_close ( &ncm->intr.ep );
|
||||
usb_endpoint_close ( &ncm->intr );
|
||||
err_open:
|
||||
ncm_rx_free ( ncm, &ncm->intr );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -312,10 +171,7 @@ static int ncm_comms_open ( struct ncm_device *ncm ) {
|
|||
static void ncm_comms_close ( struct ncm_device *ncm ) {
|
||||
|
||||
/* Close interrupt endpoint */
|
||||
usb_endpoint_close ( &ncm->intr.ep );
|
||||
|
||||
/* Free I/O buffers */
|
||||
ncm_rx_free ( ncm, &ncm->intr );
|
||||
usb_endpoint_close ( &ncm->intr );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -326,12 +182,12 @@ static void ncm_comms_close ( struct ncm_device *ncm ) {
|
|||
*/
|
||||
|
||||
/**
|
||||
* Allocate bulk IN receive ring buffers
|
||||
* Prefill bulk IN endpoint
|
||||
*
|
||||
* @v ncm CDC-NCM device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int ncm_in_alloc ( struct ncm_device *ncm ) {
|
||||
static int ncm_in_prefill ( struct ncm_device *ncm ) {
|
||||
size_t mtu;
|
||||
unsigned int count;
|
||||
int rc;
|
||||
|
@ -358,15 +214,19 @@ static int ncm_in_alloc ( struct ncm_device *ncm ) {
|
|||
count = NCM_IN_MIN_COUNT;
|
||||
if ( ( count * mtu ) > NCM_IN_MAX_SIZE )
|
||||
continue;
|
||||
if ( ( rc = ncm_rx_alloc ( ncm, &ncm->in, mtu, count ) ) != 0 )
|
||||
usb_refill_init ( &ncm->in, mtu, count );
|
||||
if ( ( rc = usb_prefill ( &ncm->in ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not prefill %dx %zd-byte "
|
||||
"buffers for bulk IN\n", ncm, count, mtu );
|
||||
continue;
|
||||
}
|
||||
|
||||
DBGC ( ncm, "NCM %p using %dx %zd-byte buffers for bulk IN\n",
|
||||
ncm, count, mtu );
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( ncm, "NCM %p could not allocate bulk IN buffers\n", ncm );
|
||||
DBGC ( ncm, "NCM %p could not prefill bulk IN endpoint\n", ncm );
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -379,7 +239,7 @@ static int ncm_in_alloc ( struct ncm_device *ncm ) {
|
|||
*/
|
||||
static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
||||
int rc ) {
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, in.ep );
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, in );
|
||||
struct net_device *netdev = ncm->netdev;
|
||||
struct ncm_transfer_header *nth;
|
||||
struct ncm_datagram_pointer *ndp;
|
||||
|
@ -404,13 +264,14 @@ static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
|||
if ( rc != 0 ) {
|
||||
DBGC ( ncm, "NCM %p bulk IN failed: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto drop;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Locate transfer header */
|
||||
len = iob_len ( iobuf );
|
||||
if ( sizeof ( *nth ) > len ) {
|
||||
DBGC ( ncm, "NCM %p packet too short for NTH:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
nth = iobuf->data;
|
||||
|
@ -419,16 +280,19 @@ static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
|||
ndp_offset = le16_to_cpu ( nth->offset );
|
||||
if ( ( ndp_offset + sizeof ( *ndp ) ) > len ) {
|
||||
DBGC ( ncm, "NCM %p packet too short for NDP:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
ndp = ( iobuf->data + ndp_offset );
|
||||
ndp_len = le16_to_cpu ( ndp->header_len );
|
||||
if ( ndp_len < offsetof ( typeof ( *ndp ), desc ) ) {
|
||||
DBGC ( ncm, "NCM %p NDP header length too short:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if ( ( ndp_offset + ndp_len ) > len ) {
|
||||
DBGC ( ncm, "NCM %p packet too short for NDP:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -445,10 +309,12 @@ static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
|||
pkt_len = le16_to_cpu ( desc->len );
|
||||
if ( pkt_len < ETH_HLEN ) {
|
||||
DBGC ( ncm, "NCM %p underlength datagram:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if ( ( pkt_offset + pkt_len ) > len ) {
|
||||
DBGC ( ncm, "NCM %p datagram exceeds packet:\n", ncm );
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -468,8 +334,7 @@ static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
|||
* received packet and reuse the same I/O buffer for
|
||||
* transmission.
|
||||
*/
|
||||
headroom = ( sizeof ( struct ncm_ntb_header ) +
|
||||
ncm->out.padding );
|
||||
headroom = ( sizeof ( struct ncm_ntb_header ) + ncm->padding );
|
||||
pkt = alloc_iob ( headroom + pkt_len );
|
||||
if ( ! pkt ) {
|
||||
/* Record error and continue */
|
||||
|
@ -490,19 +355,17 @@ static void ncm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
|||
}
|
||||
|
||||
/* Recycle I/O buffer */
|
||||
ncm_rx_recycle ( ncm, &ncm->in, iobuf );
|
||||
usb_recycle ( &ncm->in, iobuf );
|
||||
profile_stop ( &ncm_in_profiler );
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
rc = -EIO;
|
||||
drop:
|
||||
/* Record error against network device */
|
||||
DBGC_HDA ( ncm, 0, iobuf->data, iob_len ( iobuf ) );
|
||||
netdev_rx_err ( netdev, NULL, rc );
|
||||
ignore:
|
||||
ncm_rx_recycle ( ncm, &ncm->in, iobuf );
|
||||
usb_recycle ( &ncm->in, iobuf );
|
||||
}
|
||||
|
||||
/** Bulk IN endpoint operations */
|
||||
|
@ -521,7 +384,7 @@ static int ncm_out_transmit ( struct ncm_device *ncm,
|
|||
struct io_buffer *iobuf ) {
|
||||
struct ncm_ntb_header *header;
|
||||
size_t len = iob_len ( iobuf );
|
||||
size_t header_len = ( sizeof ( *header ) + ncm->out.padding );
|
||||
size_t header_len = ( sizeof ( *header ) + ncm->padding );
|
||||
int rc;
|
||||
|
||||
/* Profile transmissions */
|
||||
|
@ -535,7 +398,7 @@ static int ncm_out_transmit ( struct ncm_device *ncm,
|
|||
/* Populate header */
|
||||
header->nth.magic = cpu_to_le32 ( NCM_TRANSFER_HEADER_MAGIC );
|
||||
header->nth.header_len = cpu_to_le16 ( sizeof ( header->nth ) );
|
||||
header->nth.sequence = cpu_to_le16 ( ncm->out.sequence );
|
||||
header->nth.sequence = cpu_to_le16 ( ncm->sequence );
|
||||
header->nth.len = cpu_to_le16 ( iob_len ( iobuf ) );
|
||||
header->nth.offset =
|
||||
cpu_to_le16 ( offsetof ( typeof ( *header ), ndp ) );
|
||||
|
@ -548,11 +411,11 @@ static int ncm_out_transmit ( struct ncm_device *ncm,
|
|||
memset ( &header->desc[1], 0, sizeof ( header->desc[1] ) );
|
||||
|
||||
/* Enqueue I/O buffer */
|
||||
if ( ( rc = usb_stream ( &ncm->out.ep, iobuf, 0 ) ) != 0 )
|
||||
if ( ( rc = usb_stream ( &ncm->out, iobuf, 0 ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Increment sequence number */
|
||||
ncm->out.sequence++;
|
||||
ncm->sequence++;
|
||||
|
||||
profile_stop ( &ncm_out_profiler );
|
||||
return 0;
|
||||
|
@ -567,7 +430,7 @@ static int ncm_out_transmit ( struct ncm_device *ncm,
|
|||
*/
|
||||
static void ncm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
|
||||
int rc ) {
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, out.ep );
|
||||
struct ncm_device *ncm = container_of ( ep, struct ncm_device, out );
|
||||
struct net_device *netdev = ncm->netdev;
|
||||
|
||||
/* Report TX completion */
|
||||
|
@ -590,13 +453,13 @@ static int ncm_data_open ( struct ncm_device *ncm ) {
|
|||
struct ncm_set_ntb_input_size size;
|
||||
int rc;
|
||||
|
||||
/* Allocate I/O buffers */
|
||||
if ( ( rc = ncm_in_alloc ( ncm ) ) != 0 )
|
||||
goto err_alloc;
|
||||
/* Prefill I/O buffers */
|
||||
if ( ( rc = ncm_in_prefill ( ncm ) ) != 0 )
|
||||
goto err_prefill;
|
||||
|
||||
/* Set maximum input size */
|
||||
memset ( &size, 0, sizeof ( size ) );
|
||||
size.mtu = cpu_to_le32 ( ncm->in.mtu );
|
||||
size.mtu = cpu_to_le32 ( ncm->in.len );
|
||||
if ( ( rc = usb_control ( usb, NCM_SET_NTB_INPUT_SIZE, 0, ncm->comms,
|
||||
&size, sizeof ( size ) ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not set input size to %zd: %s\n",
|
||||
|
@ -613,33 +476,38 @@ static int ncm_data_open ( struct ncm_device *ncm ) {
|
|||
}
|
||||
|
||||
/* Open bulk IN endpoint */
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->in.ep ) ) != 0 ) {
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->in ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not open bulk IN: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_open_in;
|
||||
}
|
||||
|
||||
/* Open bulk OUT endpoint */
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->out.ep ) ) != 0 ) {
|
||||
if ( ( rc = usb_endpoint_open ( &ncm->out ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not open bulk OUT: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_open_out;
|
||||
}
|
||||
|
||||
/* Reset transmit sequence number */
|
||||
ncm->out.sequence = 0;
|
||||
/* Refill bulk IN endpoint */
|
||||
if ( ( rc = usb_refill ( &ncm->in ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not refill bulk IN: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_refill;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
usb_endpoint_close ( &ncm->out.ep );
|
||||
err_refill:
|
||||
usb_endpoint_close ( &ncm->out );
|
||||
err_open_out:
|
||||
usb_endpoint_close ( &ncm->in.ep );
|
||||
usb_endpoint_close ( &ncm->in );
|
||||
err_open_in:
|
||||
usb_set_interface ( usb, ncm->data, 0 );
|
||||
err_set_interface:
|
||||
err_set_ntb_input_size:
|
||||
ncm_rx_free ( ncm, &ncm->in );
|
||||
err_alloc:
|
||||
usb_flush ( &ncm->in );
|
||||
err_prefill:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -652,14 +520,11 @@ static void ncm_data_close ( struct ncm_device *ncm ) {
|
|||
struct usb_device *usb = ncm->usb;
|
||||
|
||||
/* Close endpoints */
|
||||
usb_endpoint_close ( &ncm->out.ep );
|
||||
usb_endpoint_close ( &ncm->in.ep );
|
||||
usb_endpoint_close ( &ncm->out );
|
||||
usb_endpoint_close ( &ncm->in );
|
||||
|
||||
/* Reset data interface */
|
||||
usb_set_interface ( usb, ncm->data, 0 );
|
||||
|
||||
/* Free I/O buffers */
|
||||
ncm_rx_free ( ncm, &ncm->in );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -680,30 +545,20 @@ static int ncm_open ( struct net_device *netdev ) {
|
|||
int rc;
|
||||
|
||||
/* Reset sequence number */
|
||||
ncm->out.sequence = 0;
|
||||
ncm->sequence = 0;
|
||||
|
||||
/* Open communications interface */
|
||||
if ( ( rc = ncm_comms_open ( ncm ) ) != 0 )
|
||||
goto err_comms_open;
|
||||
|
||||
/* Refill interrupt ring */
|
||||
if ( ( rc = ncm_rx_refill ( ncm, &ncm->intr ) ) != 0 )
|
||||
goto err_intr_refill;
|
||||
|
||||
/* Open data interface */
|
||||
if ( ( rc = ncm_data_open ( ncm ) ) != 0 )
|
||||
goto err_data_open;
|
||||
|
||||
/* Refill bulk IN ring */
|
||||
if ( ( rc = ncm_rx_refill ( ncm, &ncm->in ) ) != 0 )
|
||||
goto err_in_refill;
|
||||
|
||||
return 0;
|
||||
|
||||
err_in_refill:
|
||||
ncm_data_close ( ncm );
|
||||
err_data_open:
|
||||
err_intr_refill:
|
||||
ncm_comms_close ( ncm );
|
||||
err_comms_open:
|
||||
return rc;
|
||||
|
@ -755,12 +610,12 @@ static void ncm_poll ( struct net_device *netdev ) {
|
|||
/* Poll USB bus */
|
||||
usb_poll ( ncm->bus );
|
||||
|
||||
/* Refill interrupt ring */
|
||||
if ( ( rc = ncm_rx_refill ( ncm, &ncm->intr ) ) != 0 )
|
||||
/* Refill interrupt endpoint */
|
||||
if ( ( rc = usb_refill ( &ncm->intr ) ) != 0 )
|
||||
netdev_rx_err ( netdev, NULL, rc );
|
||||
|
||||
/* Refill bulk IN ring */
|
||||
if ( ( rc = ncm_rx_refill ( ncm, &ncm->in ) ) != 0 )
|
||||
/* Refill bulk IN endpoint */
|
||||
if ( ( rc = usb_refill ( &ncm->in ) ) != 0 )
|
||||
netdev_rx_err ( netdev, NULL, rc );
|
||||
}
|
||||
|
||||
|
@ -810,9 +665,10 @@ static int ncm_probe ( struct usb_function *func,
|
|||
ncm->usb = usb;
|
||||
ncm->bus = usb->port->hub->bus;
|
||||
ncm->netdev = netdev;
|
||||
usb_endpoint_init ( &ncm->intr.ep, usb, &ncm_intr_operations );
|
||||
usb_endpoint_init ( &ncm->in.ep, usb, &ncm_in_operations );
|
||||
usb_endpoint_init ( &ncm->out.ep, usb, &ncm_out_operations );
|
||||
usb_endpoint_init ( &ncm->intr, usb, &ncm_intr_operations );
|
||||
usb_endpoint_init ( &ncm->in, usb, &ncm_in_operations );
|
||||
usb_endpoint_init ( &ncm->out, usb, &ncm_out_operations );
|
||||
usb_refill_init ( &ncm->intr, 0, NCM_INTR_COUNT );
|
||||
DBGC ( ncm, "NCM %p on %s\n", ncm, func->name );
|
||||
|
||||
/* Identify interfaces */
|
||||
|
@ -843,7 +699,7 @@ static int ncm_probe ( struct usb_function *func,
|
|||
}
|
||||
|
||||
/* Describe interrupt endpoint */
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->intr.ep, config, comms,
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->intr, config, comms,
|
||||
USB_INTERRUPT, 0 ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not describe interrupt endpoint: "
|
||||
"%s\n", ncm, strerror ( rc ) );
|
||||
|
@ -851,7 +707,7 @@ static int ncm_probe ( struct usb_function *func,
|
|||
}
|
||||
|
||||
/* Describe bulk IN endpoint */
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->in.ep, config, data,
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->in, config, data,
|
||||
USB_BULK_IN, 0 ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not describe bulk IN endpoint: "
|
||||
"%s\n", ncm, strerror ( rc ) );
|
||||
|
@ -859,7 +715,7 @@ static int ncm_probe ( struct usb_function *func,
|
|||
}
|
||||
|
||||
/* Describe bulk OUT endpoint */
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->out.ep, config, data,
|
||||
if ( ( rc = usb_endpoint_described ( &ncm->out, config, data,
|
||||
USB_BULK_OUT, 0 ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not describe bulk OUT endpoint: "
|
||||
"%s\n", ncm, strerror ( rc ) );
|
||||
|
@ -894,12 +750,12 @@ static int ncm_probe ( struct usb_function *func,
|
|||
DBGC2 ( ncm, "NCM %p maximum IN size is %zd bytes\n", ncm, ncm->mtu );
|
||||
|
||||
/* Calculate transmit padding */
|
||||
ncm->out.padding = ( ( le16_to_cpu ( params.out.remainder ) -
|
||||
ncm->padding = ( ( le16_to_cpu ( params.out.remainder ) -
|
||||
sizeof ( struct ncm_ntb_header ) - ETH_HLEN ) &
|
||||
( le16_to_cpu ( params.out.divisor ) - 1 ) );
|
||||
DBGC2 ( ncm, "NCM %p using %zd-byte transmit padding\n",
|
||||
ncm, ncm->out.padding );
|
||||
assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->out.padding +
|
||||
ncm, ncm->padding );
|
||||
assert ( ( ( sizeof ( struct ncm_ntb_header ) + ncm->padding +
|
||||
ETH_HLEN ) % le16_to_cpu ( params.out.divisor ) ) ==
|
||||
le16_to_cpu ( params.out.remainder ) );
|
||||
|
||||
|
|
|
@ -139,26 +139,6 @@ struct ncm_ntb_header {
|
|||
struct ncm_datagram_descriptor desc[2];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** A CDC-NCM receive ring */
|
||||
struct ncm_rx_ring {
|
||||
/** USB endpoint */
|
||||
struct usb_endpoint ep;
|
||||
/** I/O buffer size */
|
||||
size_t mtu;
|
||||
/** Recycled buffer list */
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/** A CDC-NCM transmit ring */
|
||||
struct ncm_tx_ring {
|
||||
/** USB endpoint */
|
||||
struct usb_endpoint ep;
|
||||
/** Transmitted packet sequence number */
|
||||
uint16_t sequence;
|
||||
/** Alignment padding required on transmitted packets */
|
||||
size_t padding;
|
||||
};
|
||||
|
||||
/** A CDC-NCM network device */
|
||||
struct ncm_device {
|
||||
/** USB device */
|
||||
|
@ -175,13 +155,17 @@ struct ncm_device {
|
|||
|
||||
/** Maximum supported NTB input size */
|
||||
size_t mtu;
|
||||
/** Transmitted packet sequence number */
|
||||
uint16_t sequence;
|
||||
/** Alignment padding required on transmitted packets */
|
||||
size_t padding;
|
||||
|
||||
/** Interrupt ring */
|
||||
struct ncm_rx_ring intr;
|
||||
/** Bulk IN ring */
|
||||
struct ncm_rx_ring in;
|
||||
/** Bulk OUT ring */
|
||||
struct ncm_tx_ring out;
|
||||
/** Interrupt endpoint */
|
||||
struct usb_endpoint intr;
|
||||
/** Bulk IN endpoint */
|
||||
struct usb_endpoint in;
|
||||
/** Bulk OUT endpoint */
|
||||
struct usb_endpoint out;
|
||||
};
|
||||
|
||||
/** Bulk IN ring minimum buffer count
|
||||
|
|
Loading…
Reference in New Issue