xref: /netbsd-src/sys/dev/usb/if_upl.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1 /*	$NetBSD: if_upl.c,v 1.71 2020/03/15 23:04:51 thorpej 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@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.71 2020/03/15 23:04:51 thorpej 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 	usbnet_lock_core(un);
261 	if (usbnet_isdying(un))
262 		rv = EIO;
263 	else
264 		rv = usbnet_init_rx_tx(un);
265 	usbnet_unlock_core(un);
266 
267 	return rv;
268 }
269 
270 static int
271 upl_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
272 {
273 	if (cmd == SIOCSIFMTU) {
274 		struct ifreq *ifr = data;
275 
276 		if (ifr->ifr_mtu > UPL_BUFSZ)
277 			return EINVAL;
278 	}
279 	return 0;
280 }
281 
282 static int
283 upl_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
284     const struct rtentry *rt0)
285 {
286 	struct usbnet * const un __unused = ifp->if_softc;
287 
288 	DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__));
289 
290 	/* If the queueing discipline needs packet classification, do it now. */
291 	IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
292 
293 	/*
294 	 * Queue message on interface, and start output if interface
295 	 * not yet active.
296 	 */
297 	return if_transmit_lock(ifp, m);
298 }
299 
300 static void
301 upl_input(struct ifnet *ifp, struct mbuf *m)
302 {
303 #ifdef INET
304 	size_t pktlen = m->m_len;
305 	int s;
306 
307 	s = splnet();
308 	if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
309 		if_statinc(ifp, if_iqdrops);
310 		m_freem(m);
311 	} else {
312 		if_statadd2(ifp, if_ipackets, 1, if_ibytes, pktlen);
313 	}
314 	splx(s);
315 #endif
316 }
317 
318 #ifdef _MODULE
319 #include "ioconf.c"
320 #endif
321 
322 USBNET_MODULE(upl)
323