Print this page
3419 usbftdi needs to support the BeagleBone


   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*




  28  * FTDI FT232R USB UART device-specific driver
  29  *
  30  * May work on the (many) devices based on earlier versions of the chip.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/param.h>
  35 #include <sys/conf.h>
  36 #include <sys/stream.h>
  37 #include <sys/strsun.h>
  38 #include <sys/termio.h>
  39 #include <sys/termiox.h>
  40 #include <sys/ddi.h>
  41 #include <sys/sunddi.h>
  42 
  43 #define USBDRV_MAJOR_VER        2
  44 #define USBDRV_MINOR_VER        0
  45 
  46 #include <sys/usb/usba.h>
  47 #include <sys/usb/usba/usba_types.h>


 203         }
 204 
 205         uf->uf_hwport = FTDI_PIT_SIOA + uf->uf_dev_data->dev_curr_if;
 206 
 207         mutex_init(&uf->uf_lock, NULL, MUTEX_DRIVER,
 208             uf->uf_dev_data->dev_iblock_cookie);
 209 
 210         cv_init(&uf->uf_tx_cv, NULL, CV_DRIVER, NULL);
 211 
 212         uf->uf_lh = usb_alloc_log_hdl(uf->uf_dip, "uftdi",
 213             &uftdi_errlevel, &uftdi_errmask, &uftdi_instance_debug, 0);
 214 
 215         /*
 216          * This device and its clones has numerous physical instantiations.
 217          */
 218         recognized = B_TRUE;
 219         dd = uf->uf_dev_data->dev_descr;
 220         switch (dd->idVendor) {
 221         case USB_VENDOR_FTDI:
 222                 switch (dd->idProduct) {

 223                 case USB_PRODUCT_FTDI_SERIAL_8U232AM:
 224                 case USB_PRODUCT_FTDI_SEMC_DSS20:
 225                 case USB_PRODUCT_FTDI_CFA_631:
 226                 case USB_PRODUCT_FTDI_CFA_632:
 227                 case USB_PRODUCT_FTDI_CFA_633:
 228                 case USB_PRODUCT_FTDI_CFA_634:
 229                 case USB_PRODUCT_FTDI_CFA_635:
 230                 case USB_PRODUCT_FTDI_USBSERIAL:
 231                 case USB_PRODUCT_FTDI_MX2_3:
 232                 case USB_PRODUCT_FTDI_MX4_5:
 233                 case USB_PRODUCT_FTDI_LK202:
 234                 case USB_PRODUCT_FTDI_LK204:
 235                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M:
 236                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S:
 237                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U:
 238                 case USB_PRODUCT_FTDI_EISCOU:
 239                 case USB_PRODUCT_FTDI_UOPTBR:
 240                 case USB_PRODUCT_FTDI_EMCU2D:
 241                 case USB_PRODUCT_FTDI_PCMSFU:
 242                 case USB_PRODUCT_FTDI_EMCU2H:


 311             dd->idVendor, dd->idProduct, uf->uf_hwport);
 312 
 313         uf->uf_def_ph = uf->uf_dev_data->dev_default_ph;
 314 
 315         mutex_enter(&uf->uf_lock);
 316         uf->uf_dev_state = USB_DEV_ONLINE;
 317         uf->uf_port_state = UFTDI_PORT_CLOSED;
 318         mutex_exit(&uf->uf_lock);
 319 
 320         if (uftdi_create_pm_components(uf) != USB_SUCCESS) {
 321                 uftdi_cleanup(uf, 3);
 322                 return (USB_FAILURE);
 323         }
 324 
 325         if (usb_register_event_cbs(uf->uf_dip,
 326             uf->uf_usb_events, 0) != USB_SUCCESS) {
 327                 uftdi_cleanup(uf, 4);
 328                 return (USB_FAILURE);
 329         }
 330 
 331         if (usb_pipe_get_max_bulk_transfer_size(uf->uf_dip,
 332             &uf->uf_xfer_sz) != USB_SUCCESS) {
 333                 uftdi_cleanup(uf, 5);
 334                 return (USB_FAILURE);
 335         }
 336 
 337         /*
 338          * TODO: modern ftdi devices have deeper (and asymmetric)
 339          * fifos than this minimal 64 bytes .. but how to tell
 340          * -safely- ?
 341          */
 342 
 343 #define FTDI_MAX_XFERSIZE       64
 344 
 345         if (uf->uf_xfer_sz > FTDI_MAX_XFERSIZE)
 346                 uf->uf_xfer_sz = FTDI_MAX_XFERSIZE;
 347 
 348         if (uftdi_dev_attach(uf) != USB_SUCCESS) {
 349                 uftdi_cleanup(uf, 5);
 350                 return (USB_FAILURE);
 351         }
 352 
 353         return (USB_SUCCESS);
 354 }
 355 
 356 #define FTDI_CLEANUP_LEVEL_MAX  6
 357 
 358 /*
 359  * ds_detach
 360  */
 361 static void
 362 uftdi_detach(ds_hdl_t hdl)
 363 {
 364         uftdi_cleanup((uftdi_state_t *)hdl, FTDI_CLEANUP_LEVEL_MAX);
 365 }
 366 
 367 


1484         case USB_DEV_DISCONNECTED:
1485         case USB_DEV_SUSPENDED:
1486                 return (USB_SUCCESS);
1487         default:
1488                 USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh,
1489                     "uftdi_pwrlvl3: illegal device state");
1490                 return (USB_FAILURE);
1491         }
1492 }
1493 
1494 
1495 /*
1496  * pipe operations
1497  */
1498 static int
1499 uftdi_open_pipes(uftdi_state_t *uf)
1500 {
1501         int ifc, alt;
1502         usb_pipe_policy_t policy;
1503         usb_ep_data_t *in_data, *out_data;

1504 





1505         /* get ep data */
1506         ifc = uf->uf_dev_data->dev_curr_if;
1507         alt = 0;
1508 
1509         in_data = usb_lookup_ep_data(uf->uf_dip, uf->uf_dev_data, ifc, alt,
1510             0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
1511 
1512         out_data = usb_lookup_ep_data(uf->uf_dip, uf->uf_dev_data, ifc, alt,
1513             0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
1514 
1515         if (in_data == NULL || out_data == NULL) {
1516                 USB_DPRINTF_L2(DPRINT_ATTACH, uf->uf_lh,
1517                     "uftdi_open_pipes: can't get ep data");
1518                 return (USB_FAILURE);
1519         }
1520 















1521         /* open pipes */
1522         policy.pp_max_async_reqs = 2;
1523 
1524         if (usb_pipe_open(uf->uf_dip, &in_data->ep_descr, &policy,
1525             USB_FLAGS_SLEEP, &uf->uf_bulkin_ph) != USB_SUCCESS)
1526                 return (USB_FAILURE);
1527 
1528         if (usb_pipe_open(uf->uf_dip, &out_data->ep_descr, &policy,
1529             USB_FLAGS_SLEEP, &uf->uf_bulkout_ph) != USB_SUCCESS) {
1530                 usb_pipe_close(uf->uf_dip, uf->uf_bulkin_ph, USB_FLAGS_SLEEP,
1531                     NULL, NULL);
1532                 return (USB_FAILURE);
1533         }
1534 
1535         mutex_enter(&uf->uf_lock);
1536         uf->uf_bulkin_state = UFTDI_PIPE_IDLE;
1537         uf->uf_bulkout_state = UFTDI_PIPE_IDLE;
1538         mutex_exit(&uf->uf_lock);
1539 
1540         return (USB_SUCCESS);


1789         mutex_exit(&uf->uf_lock);
1790 }
1791 
1792 
1793 /*
1794  * start receiving data
1795  */
1796 static int
1797 uftdi_rx_start(uftdi_state_t *uf)
1798 {
1799         usb_bulk_req_t *br;
1800         int rval;
1801 
1802         USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_rx_start");
1803 
1804         ASSERT(mutex_owned(&uf->uf_lock));
1805 
1806         uf->uf_bulkin_state = UFTDI_PIPE_BUSY;
1807         mutex_exit(&uf->uf_lock);
1808 
1809         br = usb_alloc_bulk_req(uf->uf_dip, uf->uf_xfer_sz, USB_FLAGS_SLEEP);
1810         br->bulk_len = uf->uf_xfer_sz;
1811         br->bulk_timeout = UFTDI_BULKIN_TIMEOUT;
1812         br->bulk_cb = uftdi_bulkin_cb;
1813         br->bulk_exc_cb = uftdi_bulkin_cb;
1814         br->bulk_client_private = (usb_opaque_t)uf;
1815         br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
1816 
1817         rval = usb_pipe_bulk_xfer(uf->uf_bulkin_ph, br, 0);
1818 
1819         if (rval != USB_SUCCESS) {
1820                 USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh,
1821                     "uftdi_rx_start: xfer failed %d", rval);
1822                 usb_free_bulk_req(br);
1823         }
1824 
1825         mutex_enter(&uf->uf_lock);
1826         if (rval != USB_SUCCESS)
1827                 uf->uf_bulkin_state = UFTDI_PIPE_IDLE;
1828 
1829         return (rval);
1830 }


1844         int             rval;
1845 
1846         USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_tx_start");
1847         ASSERT(mutex_owned(&uf->uf_lock));
1848         ASSERT(uf->uf_port_state != UFTDI_PORT_CLOSED);
1849 
1850         if (xferd)
1851                 *xferd = 0;
1852         if ((uf->uf_port_flags & UFTDI_PORT_TX_STOPPED) ||
1853             uf->uf_tx_mp == NULL) {
1854                 return;
1855         }
1856         if (uf->uf_bulkout_state != UFTDI_PIPE_IDLE) {
1857                 USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh,
1858                     "uftdi_tx_start: pipe busy");
1859                 return;
1860         }
1861         ASSERT(MBLKL(uf->uf_tx_mp) > 0);
1862 
1863         /* send as much data as port can receive */
1864         len = min(msgdsize(uf->uf_tx_mp), uf->uf_xfer_sz);
1865 
1866         if (len <= 0)
1867                 return;
1868         if ((data = allocb(len, BPRI_LO)) == NULL)
1869                 return;
1870 
1871         /*
1872          * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
1873          */
1874         data_len = 0;
1875         while (data_len < len && uf->uf_tx_mp) {
1876                 mp = uf->uf_tx_mp;
1877                 copylen = min(MBLKL(mp), len - data_len);
1878                 bcopy(mp->b_rptr, data->b_wptr, copylen);
1879                 mp->b_rptr += copylen;
1880                 data->b_wptr += copylen;
1881                 data_len += copylen;
1882 
1883                 if (MBLKL(mp) < 1) {
1884                         uf->uf_tx_mp = unlinkb(mp);




   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2012 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
  29  */
  30 
  31 /*
  32  * FTDI FT232R USB UART device-specific driver
  33  *
  34  * May work on the (many) devices based on earlier versions of the chip.
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/param.h>
  39 #include <sys/conf.h>
  40 #include <sys/stream.h>
  41 #include <sys/strsun.h>
  42 #include <sys/termio.h>
  43 #include <sys/termiox.h>
  44 #include <sys/ddi.h>
  45 #include <sys/sunddi.h>
  46 
  47 #define USBDRV_MAJOR_VER        2
  48 #define USBDRV_MINOR_VER        0
  49 
  50 #include <sys/usb/usba.h>
  51 #include <sys/usb/usba/usba_types.h>


 207         }
 208 
 209         uf->uf_hwport = FTDI_PIT_SIOA + uf->uf_dev_data->dev_curr_if;
 210 
 211         mutex_init(&uf->uf_lock, NULL, MUTEX_DRIVER,
 212             uf->uf_dev_data->dev_iblock_cookie);
 213 
 214         cv_init(&uf->uf_tx_cv, NULL, CV_DRIVER, NULL);
 215 
 216         uf->uf_lh = usb_alloc_log_hdl(uf->uf_dip, "uftdi",
 217             &uftdi_errlevel, &uftdi_errmask, &uftdi_instance_debug, 0);
 218 
 219         /*
 220          * This device and its clones has numerous physical instantiations.
 221          */
 222         recognized = B_TRUE;
 223         dd = uf->uf_dev_data->dev_descr;
 224         switch (dd->idVendor) {
 225         case USB_VENDOR_FTDI:
 226                 switch (dd->idProduct) {
 227                 case USB_PRODUCT_FTDI_SERIAL_2232C:
 228                 case USB_PRODUCT_FTDI_SERIAL_8U232AM:
 229                 case USB_PRODUCT_FTDI_SEMC_DSS20:
 230                 case USB_PRODUCT_FTDI_CFA_631:
 231                 case USB_PRODUCT_FTDI_CFA_632:
 232                 case USB_PRODUCT_FTDI_CFA_633:
 233                 case USB_PRODUCT_FTDI_CFA_634:
 234                 case USB_PRODUCT_FTDI_CFA_635:
 235                 case USB_PRODUCT_FTDI_USBSERIAL:
 236                 case USB_PRODUCT_FTDI_MX2_3:
 237                 case USB_PRODUCT_FTDI_MX4_5:
 238                 case USB_PRODUCT_FTDI_LK202:
 239                 case USB_PRODUCT_FTDI_LK204:
 240                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13M:
 241                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13S:
 242                 case USB_PRODUCT_FTDI_TACTRIX_OPENPORT_13U:
 243                 case USB_PRODUCT_FTDI_EISCOU:
 244                 case USB_PRODUCT_FTDI_UOPTBR:
 245                 case USB_PRODUCT_FTDI_EMCU2D:
 246                 case USB_PRODUCT_FTDI_PCMSFU:
 247                 case USB_PRODUCT_FTDI_EMCU2H:


 316             dd->idVendor, dd->idProduct, uf->uf_hwport);
 317 
 318         uf->uf_def_ph = uf->uf_dev_data->dev_default_ph;
 319 
 320         mutex_enter(&uf->uf_lock);
 321         uf->uf_dev_state = USB_DEV_ONLINE;
 322         uf->uf_port_state = UFTDI_PORT_CLOSED;
 323         mutex_exit(&uf->uf_lock);
 324 
 325         if (uftdi_create_pm_components(uf) != USB_SUCCESS) {
 326                 uftdi_cleanup(uf, 3);
 327                 return (USB_FAILURE);
 328         }
 329 
 330         if (usb_register_event_cbs(uf->uf_dip,
 331             uf->uf_usb_events, 0) != USB_SUCCESS) {
 332                 uftdi_cleanup(uf, 4);
 333                 return (USB_FAILURE);
 334         }
 335 

















 336         if (uftdi_dev_attach(uf) != USB_SUCCESS) {
 337                 uftdi_cleanup(uf, 5);
 338                 return (USB_FAILURE);
 339         }
 340 
 341         return (USB_SUCCESS);
 342 }
 343 
 344 #define FTDI_CLEANUP_LEVEL_MAX  6
 345 
 346 /*
 347  * ds_detach
 348  */
 349 static void
 350 uftdi_detach(ds_hdl_t hdl)
 351 {
 352         uftdi_cleanup((uftdi_state_t *)hdl, FTDI_CLEANUP_LEVEL_MAX);
 353 }
 354 
 355 


1472         case USB_DEV_DISCONNECTED:
1473         case USB_DEV_SUSPENDED:
1474                 return (USB_SUCCESS);
1475         default:
1476                 USB_DPRINTF_L2(DPRINT_PM, uf->uf_lh,
1477                     "uftdi_pwrlvl3: illegal device state");
1478                 return (USB_FAILURE);
1479         }
1480 }
1481 
1482 
1483 /*
1484  * pipe operations
1485  */
1486 static int
1487 uftdi_open_pipes(uftdi_state_t *uf)
1488 {
1489         int ifc, alt;
1490         usb_pipe_policy_t policy;
1491         usb_ep_data_t *in_data, *out_data;
1492         size_t max_xfer_sz;
1493 
1494         /* get max transfer size */
1495         if (usb_pipe_get_max_bulk_transfer_size(uf->uf_dip, &max_xfer_sz)
1496             != USB_SUCCESS)
1497                 return (USB_FAILURE);
1498 
1499         /* get ep data */
1500         ifc = uf->uf_dev_data->dev_curr_if;
1501         alt = 0;
1502 
1503         in_data = usb_lookup_ep_data(uf->uf_dip, uf->uf_dev_data, ifc, alt,
1504             0, USB_EP_ATTR_BULK, USB_EP_DIR_IN);
1505 
1506         out_data = usb_lookup_ep_data(uf->uf_dip, uf->uf_dev_data, ifc, alt,
1507             0, USB_EP_ATTR_BULK, USB_EP_DIR_OUT);
1508 
1509         if (in_data == NULL || out_data == NULL) {
1510                 USB_DPRINTF_L2(DPRINT_ATTACH, uf->uf_lh,
1511                     "uftdi_open_pipes: can't get ep data");
1512                 return (USB_FAILURE);
1513         }
1514 
1515         /*
1516          * Set buffer sizes. Default to UFTDI_XFER_SZ_MAX.
1517          * Use wMaxPacketSize from endpoint descriptor if it is nonzero..
1518          * Cap at a max transfer size of host controller.
1519          */
1520         uf->uf_ibuf_sz = uf->uf_obuf_sz = UFTDI_XFER_SZ_MAX;
1521 
1522         if (in_data->ep_descr.wMaxPacketSize)
1523                 uf->uf_ibuf_sz = in_data->ep_descr.wMaxPacketSize;
1524         uf->uf_ibuf_sz = min(uf->uf_ibuf_sz, max_xfer_sz);
1525 
1526         if (out_data->ep_descr.wMaxPacketSize)
1527                 uf->uf_obuf_sz = out_data->ep_descr.wMaxPacketSize;
1528         uf->uf_obuf_sz = min(uf->uf_obuf_sz, max_xfer_sz);
1529 
1530         /* open pipes */
1531         policy.pp_max_async_reqs = 2;
1532 
1533         if (usb_pipe_open(uf->uf_dip, &in_data->ep_descr, &policy,
1534             USB_FLAGS_SLEEP, &uf->uf_bulkin_ph) != USB_SUCCESS)
1535                 return (USB_FAILURE);
1536 
1537         if (usb_pipe_open(uf->uf_dip, &out_data->ep_descr, &policy,
1538             USB_FLAGS_SLEEP, &uf->uf_bulkout_ph) != USB_SUCCESS) {
1539                 usb_pipe_close(uf->uf_dip, uf->uf_bulkin_ph, USB_FLAGS_SLEEP,
1540                     NULL, NULL);
1541                 return (USB_FAILURE);
1542         }
1543 
1544         mutex_enter(&uf->uf_lock);
1545         uf->uf_bulkin_state = UFTDI_PIPE_IDLE;
1546         uf->uf_bulkout_state = UFTDI_PIPE_IDLE;
1547         mutex_exit(&uf->uf_lock);
1548 
1549         return (USB_SUCCESS);


1798         mutex_exit(&uf->uf_lock);
1799 }
1800 
1801 
1802 /*
1803  * start receiving data
1804  */
1805 static int
1806 uftdi_rx_start(uftdi_state_t *uf)
1807 {
1808         usb_bulk_req_t *br;
1809         int rval;
1810 
1811         USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_rx_start");
1812 
1813         ASSERT(mutex_owned(&uf->uf_lock));
1814 
1815         uf->uf_bulkin_state = UFTDI_PIPE_BUSY;
1816         mutex_exit(&uf->uf_lock);
1817 
1818         br = usb_alloc_bulk_req(uf->uf_dip, uf->uf_ibuf_sz, USB_FLAGS_SLEEP);
1819         br->bulk_len = uf->uf_ibuf_sz;
1820         br->bulk_timeout = UFTDI_BULKIN_TIMEOUT;
1821         br->bulk_cb = uftdi_bulkin_cb;
1822         br->bulk_exc_cb = uftdi_bulkin_cb;
1823         br->bulk_client_private = (usb_opaque_t)uf;
1824         br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;
1825 
1826         rval = usb_pipe_bulk_xfer(uf->uf_bulkin_ph, br, 0);
1827 
1828         if (rval != USB_SUCCESS) {
1829                 USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh,
1830                     "uftdi_rx_start: xfer failed %d", rval);
1831                 usb_free_bulk_req(br);
1832         }
1833 
1834         mutex_enter(&uf->uf_lock);
1835         if (rval != USB_SUCCESS)
1836                 uf->uf_bulkin_state = UFTDI_PIPE_IDLE;
1837 
1838         return (rval);
1839 }


1853         int             rval;
1854 
1855         USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_tx_start");
1856         ASSERT(mutex_owned(&uf->uf_lock));
1857         ASSERT(uf->uf_port_state != UFTDI_PORT_CLOSED);
1858 
1859         if (xferd)
1860                 *xferd = 0;
1861         if ((uf->uf_port_flags & UFTDI_PORT_TX_STOPPED) ||
1862             uf->uf_tx_mp == NULL) {
1863                 return;
1864         }
1865         if (uf->uf_bulkout_state != UFTDI_PIPE_IDLE) {
1866                 USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh,
1867                     "uftdi_tx_start: pipe busy");
1868                 return;
1869         }
1870         ASSERT(MBLKL(uf->uf_tx_mp) > 0);
1871 
1872         /* send as much data as port can receive */
1873         len = min(msgdsize(uf->uf_tx_mp), uf->uf_obuf_sz);
1874 
1875         if (len <= 0)
1876                 return;
1877         if ((data = allocb(len, BPRI_LO)) == NULL)
1878                 return;
1879 
1880         /*
1881          * copy no more than 'len' bytes from mblk chain to transmit mblk 'data'
1882          */
1883         data_len = 0;
1884         while (data_len < len && uf->uf_tx_mp) {
1885                 mp = uf->uf_tx_mp;
1886                 copylen = min(MBLKL(mp), len - data_len);
1887                 bcopy(mp->b_rptr, data->b_wptr, copylen);
1888                 mp->b_rptr += copylen;
1889                 data->b_wptr += copylen;
1890                 data_len += copylen;
1891 
1892                 if (MBLKL(mp) < 1) {
1893                         uf->uf_tx_mp = unlinkb(mp);