if_upl.c revision 1.71 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 (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.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