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