if_upl.c revision 1.64.2.1 1 /* $NetBSD: if_upl.c,v 1.64.2.1 2019/09/01 13:00:36 martin 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.64.2.1 2019/09/01 13:00:36 martin 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 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 { 0, 0 }
100 };
101
102 int upl_match(device_t, cfdata_t, void *);
103 void upl_attach(device_t, device_t, void *);
104
105 CFATTACH_DECL_NEW(upl, sizeof(struct usbnet), upl_match, upl_attach,
106 usbnet_detach, usbnet_activate);
107
108 #if 0
109 static void upl_intr_cb(struct usbnet *, usbd_status);
110 #endif
111 static void upl_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t);
112 static unsigned upl_tx_prepare(struct usbnet *, struct mbuf *,
113 struct usbnet_chain *);
114 static int upl_ioctl_cb(struct ifnet *, u_long, void *);
115 static int upl_init(struct ifnet *);
116
117 static struct usbnet_ops upl_ops = {
118 .uno_init = upl_init,
119 .uno_tx_prepare = upl_tx_prepare,
120 .uno_rx_loop = upl_rx_loop,
121 .uno_ioctl = upl_ioctl_cb,
122 #if 0
123 .uno_intr = upl_intr_cb,
124 #endif
125 };
126
127 static int upl_output(struct ifnet *, struct mbuf *, const struct sockaddr *,
128 const struct rtentry *);
129 static void upl_input(struct ifnet *, struct mbuf *);
130
131 /*
132 * Probe for a Prolific chip.
133 */
134 int
135 upl_match(device_t parent, cfdata_t match, void *aux)
136 {
137 struct usb_attach_arg *uaa = aux;
138
139 return usb_lookup(sc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ?
140 UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
141 }
142
143 void
144 upl_attach(device_t parent, device_t self, void *aux)
145 {
146 struct usbnet * const un = device_private(self);
147 struct usb_attach_arg *uaa = aux;
148 char *devinfop;
149 struct usbd_device * dev = uaa->uaa_device;
150 usbd_status err;
151 usb_interface_descriptor_t *id;
152 usb_endpoint_descriptor_t *ed;
153 int i;
154
155 DPRINTFN(5,(" : upl_attach: un=%p, dev=%p", un, dev));
156
157 aprint_naive("\n");
158 aprint_normal("\n");
159 devinfop = usbd_devinfo_alloc(dev, 0);
160 aprint_normal_dev(self, "%s\n", devinfop);
161 usbd_devinfo_free(devinfop);
162
163 un->un_dev = self;
164 un->un_udev = dev;
165 un->un_sc = un;
166 un->un_ops = &upl_ops;
167 un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
168 un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
169 un->un_rx_list_cnt = UPL_RX_LIST_CNT;
170 un->un_tx_list_cnt = UPL_TX_LIST_CNT;
171 un->un_rx_bufsz = UPL_BUFSZ;
172 un->un_tx_bufsz = UPL_BUFSZ;
173
174 err = usbd_set_config_no(dev, UPL_CONFIG_NO, 1);
175 if (err) {
176 aprint_error_dev(self, "failed to set configuration"
177 ", err=%s\n", usbd_errstr(err));
178 return;
179 }
180
181 err = usbd_device2interface_handle(dev, UPL_IFACE_IDX, &un->un_iface);
182 if (err) {
183 aprint_error_dev(self, "getting interface handle failed\n");
184 return;
185 }
186
187 id = usbd_get_interface_descriptor(un->un_iface);
188
189 /* Find endpoints. */
190 for (i = 0; i < id->bNumEndpoints; i++) {
191 ed = usbd_interface2endpoint_descriptor(un->un_iface, i);
192 if (ed == NULL) {
193 aprint_error_dev(self, "couldn't get ep %d\n", i);
194 return;
195 }
196 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
197 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
198 un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
199 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
200 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
201 un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
202 }
203 }
204
205 if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0 /*||
206 un->un_ed[USBNET_ENDPT_INTR] == 0*/) {
207 aprint_error_dev(self, "missing endpoint\n");
208 return;
209 }
210
211 usbnet_attach(un, "upldet");
212
213 /* Initialize interface info.*/
214 struct ifnet *ifp = usbnet_ifp(un);
215 ifp->if_mtu = UPL_BUFSZ;
216 ifp->if_type = IFT_OTHER;
217 ifp->if_addrlen = 0;
218 ifp->if_hdrlen = 0;
219 ifp->if_output = upl_output;
220 ifp->_if_input = upl_input;
221 ifp->if_baudrate = 12000000;
222 ifp->if_dlt = DLT_RAW;
223
224 usbnet_attach_ifp(un, IFF_POINTOPOINT | IFF_NOARP | IFF_SIMPLEX,
225 0, NULL);
226 }
227
228 static void
229 upl_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len)
230 {
231 usbnet_isowned_rx(un);
232
233 DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
234 device_xname(un->un_dev), __func__, status, total_len));
235
236 usbnet_input(un, c->unc_buf, total_len);
237 }
238
239 static unsigned
240 upl_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
241 {
242 int total_len;
243
244 if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz)
245 return 0;
246
247 m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf);
248 total_len = m->m_pkthdr.len;
249
250 DPRINTFN(10,("%s: %s: total_len=%d\n",
251 device_xname(un->un_dev), __func__, total_len));
252
253 return total_len;
254 }
255
256 static int
257 upl_init(struct ifnet *ifp)
258 {
259 struct usbnet * const un = ifp->if_softc;
260 int rv;
261
262 usbnet_lock(un);
263 if (usbnet_isdying(un))
264 rv = EIO;
265 else
266 rv = usbnet_init_rx_tx(un);
267 usbnet_unlock(un);
268
269 return rv;
270 }
271
272 static int
273 upl_ioctl_cb(struct ifnet *ifp, u_long cmd, void *data)
274 {
275 if (cmd == SIOCSIFMTU) {
276 struct ifreq *ifr = data;
277
278 if (ifr->ifr_mtu > UPL_BUFSZ)
279 return EINVAL;
280 }
281 return 0;
282 }
283
284 static int
285 upl_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
286 const struct rtentry *rt0)
287 {
288 struct usbnet * const un __unused = ifp->if_softc;
289
290 DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__));
291
292 /* If the queueing discipline needs packet classification, do it now. */
293 IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family);
294
295 /*
296 * Queue message on interface, and start output if interface
297 * not yet active.
298 */
299 return if_transmit_lock(ifp, m);
300 }
301
302 static void
303 upl_input(struct ifnet *ifp, struct mbuf *m)
304 {
305 #ifdef INET
306 size_t pktlen = m->m_len;
307 int s;
308
309 s = splnet();
310 if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) {
311 ifp->if_iqdrops++;
312 m_freem(m);
313 } else {
314 ifp->if_ipackets++;
315 ifp->if_ibytes += pktlen;
316 }
317 splx(s);
318 #endif
319 }
320
321 #ifdef _MODULE
322 #include "ioconf.c"
323 #endif
324
325 USBNET_MODULE(upl)
326