xref: /openbmc/linux/drivers/staging/vt6656/usbpipe.c (revision 160b8e75)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
4  * All rights reserved.
5  *
6  * File: usbpipe.c
7  *
8  * Purpose: Handle USB control endpoint
9  *
10  * Author: Warren Hsu
11  *
12  * Date: Mar. 29, 2005
13  *
14  * Functions:
15  *	vnt_control_out - Write variable length bytes to MEM/BB/MAC/EEPROM
16  *	vnt_control_in - Read variable length bytes from MEM/BB/MAC/EEPROM
17  *	vnt_control_out_u8 - Write one byte to MEM/BB/MAC/EEPROM
18  *	vnt_control_in_u8 - Read one byte from MEM/BB/MAC/EEPROM
19  *
20  * Revision History:
21  *      04-05-2004 Jerry Chen: Initial release
22  *      11-24-2004 Warren Hsu: Add ControlvWriteByte,ControlvReadByte,
23  *                             ControlvMaskByte
24  *
25  */
26 
27 #include "int.h"
28 #include "rxtx.h"
29 #include "dpc.h"
30 #include "desc.h"
31 #include "device.h"
32 #include "usbpipe.h"
33 
34 #define USB_CTL_WAIT	500 /* ms */
35 
36 int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
37 		    u16 index, u16 length, u8 *buffer)
38 {
39 	int status = 0;
40 	u8 *usb_buffer;
41 
42 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
43 		return STATUS_FAILURE;
44 
45 	mutex_lock(&priv->usb_lock);
46 
47 	usb_buffer = kmemdup(buffer, length, GFP_KERNEL);
48 	if (!usb_buffer) {
49 		mutex_unlock(&priv->usb_lock);
50 		return -ENOMEM;
51 	}
52 
53 	status = usb_control_msg(priv->usb,
54 				 usb_sndctrlpipe(priv->usb, 0),
55 				 request, 0x40, value,
56 				 index, usb_buffer, length, USB_CTL_WAIT);
57 
58 	kfree(usb_buffer);
59 
60 	mutex_unlock(&priv->usb_lock);
61 
62 	if (status < (int)length)
63 		return STATUS_FAILURE;
64 
65 	return STATUS_SUCCESS;
66 }
67 
68 void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 data)
69 {
70 	vnt_control_out(priv, MESSAGE_TYPE_WRITE,
71 			reg_off, reg, sizeof(u8), &data);
72 }
73 
74 int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
75 		   u16 index, u16 length, u8 *buffer)
76 {
77 	int status;
78 	u8 *usb_buffer;
79 
80 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags))
81 		return STATUS_FAILURE;
82 
83 	mutex_lock(&priv->usb_lock);
84 
85 	usb_buffer = kmalloc(length, GFP_KERNEL);
86 	if (!usb_buffer) {
87 		mutex_unlock(&priv->usb_lock);
88 		return -ENOMEM;
89 	}
90 
91 	status = usb_control_msg(priv->usb,
92 				 usb_rcvctrlpipe(priv->usb, 0),
93 				 request, 0xc0, value,
94 				 index, usb_buffer, length, USB_CTL_WAIT);
95 
96 	if (status == length)
97 		memcpy(buffer, usb_buffer, length);
98 
99 	kfree(usb_buffer);
100 
101 	mutex_unlock(&priv->usb_lock);
102 
103 	if (status < (int)length)
104 		return STATUS_FAILURE;
105 
106 	return STATUS_SUCCESS;
107 }
108 
109 void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
110 {
111 	vnt_control_in(priv, MESSAGE_TYPE_READ,
112 		       reg_off, reg, sizeof(u8), data);
113 }
114 
115 static void vnt_start_interrupt_urb_complete(struct urb *urb)
116 {
117 	struct vnt_private *priv = urb->context;
118 	int status = urb->status;
119 
120 	switch (status) {
121 	case 0:
122 	case -ETIMEDOUT:
123 		break;
124 	case -ECONNRESET:
125 	case -ENOENT:
126 	case -ESHUTDOWN:
127 		priv->int_buf.in_use = false;
128 		return;
129 	default:
130 		break;
131 	}
132 
133 	if (status) {
134 		priv->int_buf.in_use = false;
135 
136 		dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
137 	} else {
138 		vnt_int_process_data(priv);
139 	}
140 
141 	status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
142 	if (status)
143 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
144 	else
145 		priv->int_buf.in_use = true;
146 }
147 
148 int vnt_start_interrupt_urb(struct vnt_private *priv)
149 {
150 	int status = STATUS_FAILURE;
151 
152 	if (priv->int_buf.in_use)
153 		return STATUS_FAILURE;
154 
155 	priv->int_buf.in_use = true;
156 
157 	usb_fill_int_urb(priv->interrupt_urb,
158 			 priv->usb,
159 			 usb_rcvintpipe(priv->usb, 1),
160 			 priv->int_buf.data_buf,
161 			 MAX_INTERRUPT_SIZE,
162 			 vnt_start_interrupt_urb_complete,
163 			 priv,
164 			 priv->int_interval);
165 
166 	status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
167 	if (status) {
168 		dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
169 		priv->int_buf.in_use = false;
170 	}
171 
172 	return status;
173 }
174 
175 static void vnt_submit_rx_urb_complete(struct urb *urb)
176 {
177 	struct vnt_rcb *rcb = urb->context;
178 	struct vnt_private *priv = rcb->priv;
179 
180 	switch (urb->status) {
181 	case 0:
182 		break;
183 	case -ECONNRESET:
184 	case -ENOENT:
185 	case -ESHUTDOWN:
186 		return;
187 	case -ETIMEDOUT:
188 	default:
189 		dev_dbg(&priv->usb->dev, "BULK In failed %d\n", urb->status);
190 		break;
191 	}
192 
193 	if (urb->actual_length) {
194 		if (vnt_rx_data(priv, rcb, urb->actual_length)) {
195 			rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
196 			if (!rcb->skb) {
197 				dev_dbg(&priv->usb->dev,
198 					"Failed to re-alloc rx skb\n");
199 
200 				rcb->in_use = false;
201 				return;
202 			}
203 		} else {
204 			skb_push(rcb->skb, skb_headroom(rcb->skb));
205 			skb_trim(rcb->skb, 0);
206 		}
207 
208 		urb->transfer_buffer = skb_put(rcb->skb,
209 						skb_tailroom(rcb->skb));
210 	}
211 
212 	if (usb_submit_urb(urb, GFP_ATOMIC)) {
213 		dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
214 
215 		rcb->in_use = false;
216 	}
217 }
218 
219 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
220 {
221 	int status = 0;
222 	struct urb *urb = rcb->urb;
223 
224 	if (!rcb->skb) {
225 		dev_dbg(&priv->usb->dev, "rcb->skb is null\n");
226 		return status;
227 	}
228 
229 	usb_fill_bulk_urb(urb,
230 			  priv->usb,
231 			  usb_rcvbulkpipe(priv->usb, 2),
232 			  skb_put(rcb->skb, skb_tailroom(rcb->skb)),
233 			  MAX_TOTAL_SIZE_WITH_ALL_HEADERS,
234 			  vnt_submit_rx_urb_complete,
235 			  rcb);
236 
237 	status = usb_submit_urb(urb, GFP_ATOMIC);
238 	if (status) {
239 		dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", status);
240 		return STATUS_FAILURE;
241 	}
242 
243 	rcb->in_use = true;
244 
245 	return status;
246 }
247 
248 static void vnt_tx_context_complete(struct urb *urb)
249 {
250 	struct vnt_usb_send_context *context = urb->context;
251 	struct vnt_private *priv = context->priv;
252 
253 	switch (urb->status) {
254 	case 0:
255 		dev_dbg(&priv->usb->dev, "Write %d bytes\n", context->buf_len);
256 		break;
257 	case -ECONNRESET:
258 	case -ENOENT:
259 	case -ESHUTDOWN:
260 		context->in_use = false;
261 		return;
262 	case -ETIMEDOUT:
263 	default:
264 		dev_dbg(&priv->usb->dev, "BULK Out failed %d\n", urb->status);
265 		break;
266 	}
267 
268 	if (context->type == CONTEXT_DATA_PACKET)
269 		ieee80211_wake_queues(priv->hw);
270 
271 	if (urb->status || context->type == CONTEXT_BEACON_PACKET) {
272 		if (context->skb)
273 			ieee80211_free_txskb(priv->hw, context->skb);
274 
275 		context->in_use = false;
276 	}
277 }
278 
279 int vnt_tx_context(struct vnt_private *priv,
280 		   struct vnt_usb_send_context *context)
281 {
282 	int status;
283 	struct urb *urb = context->urb;
284 
285 	if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
286 		context->in_use = false;
287 		return STATUS_RESOURCES;
288 	}
289 
290 	usb_fill_bulk_urb(urb,
291 			  priv->usb,
292 			  usb_sndbulkpipe(priv->usb, 3),
293 			  context->data,
294 			  context->buf_len,
295 			  vnt_tx_context_complete,
296 			  context);
297 
298 	status = usb_submit_urb(urb, GFP_ATOMIC);
299 	if (status) {
300 		dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
301 
302 		context->in_use = false;
303 		return STATUS_FAILURE;
304 	}
305 
306 	return STATUS_PENDING;
307 }
308