Home | History | Annotate | Line # | Download | only in usb
if_upl.c revision 1.65
      1  1.65       mrg /*	$NetBSD: if_upl.c,v 1.65 2019/08/18 09:29:38 mrg Exp $	*/
      2  1.65       mrg 
      3   1.1  augustss /*
      4   1.1  augustss  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5   1.1  augustss  * All rights reserved.
      6   1.1  augustss  *
      7   1.1  augustss  * This code is derived from software contributed to The NetBSD Foundation
      8   1.3  augustss  * by Lennart Augustsson (lennart (at) augustsson.net) at
      9   1.1  augustss  * Carlstedt Research & Technology.
     10   1.1  augustss  *
     11   1.1  augustss  * Redistribution and use in source and binary forms, with or without
     12   1.1  augustss  * modification, are permitted provided that the following conditions
     13   1.1  augustss  * are met:
     14   1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     15   1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     16   1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     17   1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     18   1.1  augustss  *    documentation and/or other materials provided with the distribution.
     19   1.1  augustss  *
     20   1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21   1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22   1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23   1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24   1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25   1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26   1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27   1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28   1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29   1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30   1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     31   1.1  augustss  */
     32   1.1  augustss 
     33   1.1  augustss /*
     34   1.1  augustss  * Prolific PL2301/PL2302 driver
     35   1.1  augustss  */
     36  1.16     lukem 
     37  1.16     lukem #include <sys/cdefs.h>
     38  1.65       mrg __KERNEL_RCSID(0, "$NetBSD: if_upl.c,v 1.65 2019/08/18 09:29:38 mrg Exp $");
     39   1.1  augustss 
     40  1.44  christos #ifdef _KERNEL_OPT
     41   1.1  augustss #include "opt_inet.h"
     42  1.57     skrll #include "opt_usb.h"
     43  1.44  christos #endif
     44   1.1  augustss 
     45   1.1  augustss #include <sys/param.h>
     46   1.1  augustss 
     47  1.65       mrg #include <dev/usb/usbnet.h>
     48   1.1  augustss 
     49   1.1  augustss #include <net/if_types.h>
     50   1.1  augustss 
     51   1.1  augustss #ifdef INET
     52  1.19  augustss #include <netinet/in.h>
     53  1.19  augustss #include <netinet/in_var.h>
     54   1.1  augustss #include <netinet/if_inarp.h>
     55   1.1  augustss #endif
     56   1.1  augustss 
     57   1.1  augustss /*
     58   1.1  augustss  * 7  6  5  4  3  2  1  0
     59   1.6  augustss  * tx rx 1  0
     60   1.1  augustss  * 1110 0000 rxdata
     61   1.1  augustss  * 1010 0000 idle
     62   1.1  augustss  * 0010 0000 tx over
     63   1.1  augustss  * 0110      tx over + rxd
     64   1.1  augustss  */
     65   1.1  augustss 
     66   1.1  augustss #define UPL_RXDATA		0x40
     67   1.1  augustss #define UPL_TXOK		0x80
     68   1.1  augustss 
     69   1.1  augustss #define UPL_CONFIG_NO		1
     70   1.1  augustss #define UPL_IFACE_IDX		0
     71   1.1  augustss 
     72   1.1  augustss /***/
     73   1.1  augustss 
     74   1.1  augustss #define UPL_INTR_INTERVAL	20
     75   1.1  augustss 
     76   1.1  augustss #define UPL_BUFSZ		1024
     77   1.1  augustss 
     78   1.1  augustss #define UPL_RX_LIST_CNT		1
     79   1.1  augustss #define UPL_TX_LIST_CNT		1
     80   1.1  augustss 
     81   1.1  augustss #ifdef UPL_DEBUG
     82  1.38    dyoung #define DPRINTF(x)	if (upldebug) printf x
     83  1.38    dyoung #define DPRINTFN(n,x)	if (upldebug >= (n)) printf x
     84   1.1  augustss int	upldebug = 0;
     85   1.1  augustss #else
     86   1.1  augustss #define DPRINTF(x)
     87   1.1  augustss #define DPRINTFN(n,x)
     88   1.1  augustss #endif
     89   1.1  augustss 
     90   1.1  augustss /*
     91   1.1  augustss  * Various supported device vendors/products.
     92   1.1  augustss  */
     93  1.65       mrg static struct usb_devno sc_devs[] = {
     94   1.1  augustss 	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301 },
     95   1.1  augustss 	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302 },
     96  1.65       mrg 	{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL25A1 },
     97  1.65       mrg 	{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258 },
     98  1.65       mrg 	{ USB_VENDOR_NI, USB_PRODUCT_NI_HTOH_7825 },
     99   1.1  augustss 	{ 0, 0 }
    100   1.1  augustss };
    101   1.1  augustss 
    102  1.56   msaitoh int	upl_match(device_t, cfdata_t, void *);
    103  1.56   msaitoh void	upl_attach(device_t, device_t, void *);
    104  1.63       mrg 
    105  1.65       mrg CFATTACH_DECL_NEW(upl, sizeof(struct usbnet), upl_match, upl_attach,
    106  1.65       mrg     usbnet_detach, usbnet_activate);
    107   1.1  augustss 
    108  1.65       mrg #if 0
    109  1.65       mrg static void upl_intr_cb(struct usbnet *, usbd_status);
    110  1.65       mrg #endif
    111  1.65       mrg static void upl_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
    112  1.65       mrg static unsigned upl_tx_prepare(struct usbnet *, struct mbuf *,
    113  1.65       mrg 			       struct usbnet_chain *);
    114  1.65       mrg static int upl_ioctl_cb(struct ifnet *, u_long, void *);
    115  1.65       mrg static int upl_init(struct ifnet *);
    116  1.65       mrg 
    117  1.65       mrg static struct usbnet_ops upl_ops = {
    118  1.65       mrg 	.uno_init = upl_init,
    119  1.65       mrg 	.uno_tx_prepare = upl_tx_prepare,
    120  1.65       mrg 	.uno_rx_loop = upl_rx_loop,
    121  1.65       mrg 	.uno_ioctl = upl_ioctl_cb,
    122  1.65       mrg #if 0
    123  1.65       mrg 	.uno_intr = upl_intr_cb,
    124  1.65       mrg #endif
    125  1.65       mrg };
    126   1.4  augustss 
    127  1.65       mrg static int upl_output(struct ifnet *, struct mbuf *, const struct sockaddr *,
    128  1.52     ozaki 		      const struct rtentry *);
    129  1.65       mrg static void upl_input(struct ifnet *, struct mbuf *);
    130   1.1  augustss 
    131   1.1  augustss /*
    132   1.1  augustss  * Probe for a Prolific chip.
    133   1.1  augustss  */
    134  1.44  christos int
    135  1.38    dyoung upl_match(device_t parent, cfdata_t match, void *aux)
    136   1.1  augustss {
    137  1.38    dyoung 	struct usb_attach_arg *uaa = aux;
    138   1.1  augustss 
    139  1.65       mrg 	return usb_lookup(sc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ?
    140  1.65       mrg 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
    141   1.1  augustss }
    142   1.1  augustss 
    143  1.44  christos void
    144  1.38    dyoung upl_attach(device_t parent, device_t self, void *aux)
    145   1.1  augustss {
    146  1.65       mrg 	struct usbnet * const	un = device_private(self);
    147  1.65       mrg 	struct usb_attach_arg	*uaa = aux;
    148  1.22  augustss 	char			*devinfop;
    149  1.51     skrll 	struct usbd_device *	dev = uaa->uaa_device;
    150   1.1  augustss 	usbd_status		err;
    151   1.1  augustss 	usb_interface_descriptor_t	*id;
    152   1.1  augustss 	usb_endpoint_descriptor_t	*ed;
    153   1.1  augustss 	int			i;
    154   1.1  augustss 
    155  1.65       mrg 	DPRINTFN(5,(" : upl_attach: un=%p, dev=%p", un, dev));
    156  1.32      cube 
    157  1.34    plunky 	aprint_naive("\n");
    158  1.34    plunky 	aprint_normal("\n");
    159  1.22  augustss 	devinfop = usbd_devinfo_alloc(dev, 0);
    160  1.32      cube 	aprint_normal_dev(self, "%s\n", devinfop);
    161  1.22  augustss 	usbd_devinfo_free(devinfop);
    162   1.1  augustss 
    163  1.65       mrg 	un->un_dev = self;
    164  1.65       mrg 	un->un_udev = dev;
    165  1.65       mrg 	un->un_sc = un;
    166  1.65       mrg 	un->un_ops = &upl_ops;
    167  1.65       mrg 	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
    168  1.65       mrg 	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
    169  1.65       mrg 	un->un_rx_list_cnt = UPL_RX_LIST_CNT;
    170  1.65       mrg 	un->un_tx_list_cnt = UPL_TX_LIST_CNT;
    171  1.65       mrg 	un->un_rx_bufsz = UPL_BUFSZ;
    172  1.65       mrg 	un->un_tx_bufsz = UPL_BUFSZ;
    173  1.65       mrg 
    174   1.9  augustss 	err = usbd_set_config_no(dev, UPL_CONFIG_NO, 1);
    175   1.1  augustss 	if (err) {
    176  1.43     skrll 		aprint_error_dev(self, "failed to set configuration"
    177  1.43     skrll 		    ", err=%s\n", usbd_errstr(err));
    178  1.38    dyoung 		return;
    179   1.1  augustss 	}
    180   1.1  augustss 
    181  1.65       mrg 	err = usbd_device2interface_handle(dev, UPL_IFACE_IDX, &un->un_iface);
    182   1.1  augustss 	if (err) {
    183  1.32      cube 		aprint_error_dev(self, "getting interface handle failed\n");
    184  1.38    dyoung 		return;
    185   1.1  augustss 	}
    186   1.1  augustss 
    187  1.65       mrg 	id = usbd_get_interface_descriptor(un->un_iface);
    188   1.1  augustss 
    189   1.1  augustss 	/* Find endpoints. */
    190   1.1  augustss 	for (i = 0; i < id->bNumEndpoints; i++) {
    191  1.65       mrg 		ed = usbd_interface2endpoint_descriptor(un->un_iface, i);
    192   1.1  augustss 		if (ed == NULL) {
    193  1.32      cube 			aprint_error_dev(self, "couldn't get ep %d\n", i);
    194  1.38    dyoung 			return;
    195   1.1  augustss 		}
    196   1.1  augustss 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    197   1.1  augustss 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    198  1.65       mrg 			un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
    199   1.1  augustss 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    200   1.1  augustss 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    201  1.65       mrg 			un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
    202   1.1  augustss 		}
    203   1.1  augustss 	}
    204   1.1  augustss 
    205  1.65       mrg 	if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0 /*||
    206  1.65       mrg 	    un->un_ed[USBNET_ENDPT_INTR] == 0*/) {
    207  1.32      cube 		aprint_error_dev(self, "missing endpoint\n");
    208  1.38    dyoung 		return;
    209   1.1  augustss 	}
    210   1.1  augustss 
    211  1.65       mrg 	usbnet_attach(un, "upldet");
    212   1.1  augustss 
    213   1.1  augustss 	/* Initialize interface info.*/
    214  1.65       mrg 	struct ifnet *ifp = usbnet_ifp(un);
    215   1.1  augustss 	ifp->if_mtu = UPL_BUFSZ;
    216   1.1  augustss 	ifp->if_type = IFT_OTHER;
    217   1.1  augustss 	ifp->if_addrlen = 0;
    218   1.1  augustss 	ifp->if_hdrlen = 0;
    219   1.1  augustss 	ifp->if_output = upl_output;
    220  1.49     ozaki 	ifp->_if_input = upl_input;
    221   1.1  augustss 	ifp->if_baudrate = 12000000;
    222  1.12  augustss 	ifp->if_dlt = DLT_RAW;
    223   1.1  augustss 
    224  1.65       mrg 	usbnet_attach_ifp(un, false, IFF_POINTOPOINT | IFF_NOARP | IFF_SIMPLEX,
    225  1.65       mrg 	    0, 0);
    226   1.1  augustss }
    227   1.1  augustss 
    228  1.65       mrg static void
    229  1.65       mrg upl_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len)
    230   1.1  augustss {
    231  1.65       mrg 	usbnet_isowned_rx(un);
    232   1.1  augustss 
    233  1.65       mrg 	DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
    234  1.65       mrg 		    device_xname(un->un_dev), __func__, status, total_len));
    235   1.1  augustss 
    236  1.65       mrg 	usbnet_input(un, c->unc_buf, total_len);
    237   1.1  augustss }
    238   1.1  augustss 
    239  1.65       mrg static unsigned
    240  1.65       mrg upl_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
    241   1.1  augustss {
    242  1.65       mrg 	int	total_len;
    243   1.1  augustss 
    244  1.65       mrg 	if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz)
    245  1.35    dyoung 		return 0;
    246   1.1  augustss 
    247  1.65       mrg 	m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf);
    248   1.1  augustss 	total_len = m->m_pkthdr.len;
    249   1.1  augustss 
    250   1.1  augustss 	DPRINTFN(10,("%s: %s: total_len=%d\n",
    251  1.65       mrg 		     device_xname(un->un_dev), __func__, total_len));
    252   1.1  augustss 
    253  1.65       mrg 	return total_len;
    254   1.1  augustss }
    255   1.1  augustss 
    256  1.65       mrg static int
    257  1.65       mrg upl_init(struct ifnet *ifp)
    258   1.1  augustss {
    259  1.65       mrg 	struct usbnet * const un = ifp->if_softc;
    260  1.65       mrg 	int rv;
    261   1.1  augustss 
    262  1.65       mrg 	usbnet_lock(un);
    263  1.65       mrg 	if (usbnet_isdying(un))
    264  1.65       mrg 		rv = EIO;
    265  1.65       mrg 	else
    266  1.65       mrg 		rv = usbnet_init_rx_tx(un);
    267  1.65       mrg 	usbnet_unlock(un);
    268   1.1  augustss 
    269  1.65       mrg 	return rv;
    270   1.1  augustss }
    271   1.1  augustss 
    272  1.65       mrg static int
    273  1.65       mrg upl_ioctl_cb(struct ifnet *ifp, u_long cmd, void *data)
    274   1.1  augustss {
    275  1.65       mrg 	if (cmd == SIOCSIFMTU) {
    276  1.65       mrg 		struct ifreq *ifr = data;
    277   1.1  augustss 
    278  1.65       mrg 		if (ifr->ifr_mtu > UPL_BUFSZ)
    279  1.65       mrg 			return EINVAL;
    280   1.1  augustss 	}
    281  1.51     skrll 	return 0;
    282   1.1  augustss }
    283   1.1  augustss 
    284  1.65       mrg static int
    285  1.27    dyoung upl_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
    286  1.52     ozaki     const struct rtentry *rt0)
    287   1.1  augustss {
    288  1.65       mrg 	struct usbnet * const un __unused = ifp->if_softc;
    289   1.1  augustss 
    290  1.65       mrg 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__));
    291   1.1  augustss 
    292  1.65       mrg 	/* If the queueing discipline needs packet classification, do it now. */
    293  1.50  knakahar 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
    294  1.17    itojun 
    295   1.1  augustss 	/*
    296   1.1  augustss 	 * Queue message on interface, and start output if interface
    297   1.1  augustss 	 * not yet active.
    298   1.1  augustss 	 */
    299  1.65       mrg 	return if_transmit_lock(ifp, m);
    300   1.1  augustss }
    301   1.1  augustss 
    302  1.65       mrg static void
    303   1.4  augustss upl_input(struct ifnet *ifp, struct mbuf *m)
    304   1.1  augustss {
    305  1.21  christos #ifdef INET
    306  1.46     rmind 	size_t pktlen = m->m_len;
    307   1.1  augustss 	int s;
    308   1.1  augustss 
    309  1.14   thorpej 	s = splnet();
    310  1.46     rmind 	if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
    311   1.1  augustss 		ifp->if_iqdrops++;
    312  1.46     rmind 		m_freem(m);
    313  1.46     rmind 	} else {
    314  1.46     rmind 		ifp->if_ipackets++;
    315  1.46     rmind 		ifp->if_ibytes += pktlen;
    316   1.1  augustss 	}
    317   1.1  augustss 	splx(s);
    318  1.21  christos #endif
    319   1.1  augustss }
    320  1.65       mrg 
    321  1.65       mrg #ifdef _MODULE
    322  1.65       mrg #include "ioconf.c"
    323  1.65       mrg #endif
    324  1.65       mrg 
    325  1.65       mrg USBNET_MODULE(upl)
    326