xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/usb/usbdrv.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #define ATH_MODULE_NAME hif
20 #include "a_debug.h"
21 #include "hif_usb_internal.h"
22 #include "if_usb.h"
23 #include "cds_api.h"
24 #include "hif_debug.h"
25 
26 #define IS_BULK_EP(attr) (((attr) & 3) == 0x02)
27 #define IS_INT_EP(attr) (((attr) & 3) == 0x03)
28 #define IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
29 #define IS_DIR_IN(addr) ((addr) & 0x80)
30 
31 #define IS_FW_CRASH_DUMP(x)(((x == FW_ASSERT_PATTERN) || \
32 				(x == FW_REG_PATTERN) || \
33 				((x & FW_RAMDUMP_PATTERN_MASK) ==  \
34 						FW_RAMDUMP_PATTERN)) ? 1 : 0)
35 
36 static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
37 					int buffer_length);
38 static void usb_hif_post_recv_bundle_transfers
39 						(struct HIF_USB_PIPE *recv_pipe,
40 						int buffer_length);
41 static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context);
42 
43 
44 /**
45  * usb_hif_free_urb_to_pipe() - add urb back to urb list of a pipe
46  * @pipe: pointer to struct HIF_USB_PIPE
47  * @urb_context: pointer to struct HIF_URB_CONTEXT
48  *
49  * Return: none
50  */
51 static void usb_hif_free_urb_to_pipe(struct HIF_USB_PIPE *pipe,
52 					struct HIF_URB_CONTEXT *urb_context)
53 {
54 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
55 	pipe->urb_cnt++;
56 	DL_ListAdd(&pipe->urb_list_head, &urb_context->link);
57 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
58 }
59 
60 /**
61  * usb_hif_alloc_urb_from_pipe() - remove urb back from urb list of a pipe
62  * @pipe: pointer to struct HIF_USB_PIPE
63  *
64  * Return: struct HIF_URB_CONTEXT urb context removed from the urb list
65  */
66 struct HIF_URB_CONTEXT *usb_hif_alloc_urb_from_pipe(struct HIF_USB_PIPE *pipe)
67 {
68 	struct HIF_URB_CONTEXT *urb_context = NULL;
69 	DL_LIST *item;
70 
71 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
72 	item = dl_list_remove_item_from_head(&pipe->urb_list_head);
73 	if (item != NULL) {
74 		urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
75 						  link);
76 		pipe->urb_cnt--;
77 	}
78 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
79 
80 	return urb_context;
81 }
82 
83 /**
84  * usb_hif_dequeue_pending_transfer() - remove urb from pending xfer list
85  * @pipe: pointer to struct HIF_USB_PIPE
86  *
87  * Return: struct HIF_URB_CONTEXT urb context removed from the pending xfer list
88  */
89 static struct HIF_URB_CONTEXT *usb_hif_dequeue_pending_transfer
90 						(struct HIF_USB_PIPE *pipe)
91 {
92 	struct HIF_URB_CONTEXT *urb_context = NULL;
93 	DL_LIST *item;
94 
95 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
96 	item = dl_list_remove_item_from_head(&pipe->urb_pending_list);
97 	if (item != NULL)
98 		urb_context = A_CONTAINING_STRUCT(item, struct HIF_URB_CONTEXT,
99 						  link);
100 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
101 
102 	return urb_context;
103 }
104 
105 /**
106  * usb_hif_enqueue_pending_transfer() - add urb to pending xfer list
107  * @pipe: pointer to struct HIF_USB_PIPE
108  * @urb_context: pointer to struct HIF_URB_CONTEXT to be added to the xfer list
109  *
110  * Return: none
111  */
112 void usb_hif_enqueue_pending_transfer(struct HIF_USB_PIPE *pipe,
113 					struct HIF_URB_CONTEXT *urb_context)
114 {
115 	qdf_spin_lock_irqsave(&pipe->device->cs_lock);
116 	dl_list_insert_tail(&pipe->urb_pending_list, &urb_context->link);
117 	qdf_spin_unlock_irqrestore(&pipe->device->cs_lock);
118 }
119 
120 
121 /**
122  * usb_hif_remove_pending_transfer() - remove urb from its own list
123  * @urb_context: pointer to struct HIF_URB_CONTEXT to be removed
124  *
125  * Return: none
126  */
127 void
128 usb_hif_remove_pending_transfer(struct HIF_URB_CONTEXT *urb_context)
129 {
130 	qdf_spin_lock_irqsave(&urb_context->pipe->device->cs_lock);
131 	dl_list_remove(&urb_context->link);
132 	qdf_spin_unlock_irqrestore(&urb_context->pipe->device->cs_lock);
133 }
134 
135 /**
136  * usb_hif_alloc_pipe_resources() - allocate urb_cnt urbs to a HIF pipe
137  * @pipe: pointer to struct HIF_USB_PIPE to which resources will be allocated
138  * @urb_cnt: number of urbs to be added to the HIF pipe
139  *
140  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
141  */
142 static QDF_STATUS usb_hif_alloc_pipe_resources
143 					(struct HIF_USB_PIPE *pipe, int urb_cnt)
144 {
145 	QDF_STATUS status = QDF_STATUS_SUCCESS;
146 	int i;
147 	struct HIF_URB_CONTEXT *urb_context;
148 
149 	DL_LIST_INIT(&pipe->urb_list_head);
150 	DL_LIST_INIT(&pipe->urb_pending_list);
151 
152 	for (i = 0; i < urb_cnt; i++) {
153 		urb_context = qdf_mem_malloc(sizeof(*urb_context));
154 		if (NULL == urb_context) {
155 			status = QDF_STATUS_E_NOMEM;
156 			HIF_ERROR("urb_context is null");
157 			break;
158 		}
159 		urb_context->pipe = pipe;
160 		urb_context->urb = usb_alloc_urb(0, GFP_KERNEL);
161 
162 		if (NULL == urb_context->urb) {
163 			status = QDF_STATUS_E_NOMEM;
164 			qdf_mem_free(urb_context);
165 			HIF_ERROR("urb_context->urb is null");
166 			break;
167 		}
168 
169 		/* note we are only allocate the urb contexts here, the actual
170 		 * URB is
171 		 * allocated from the kernel as needed to do a transaction
172 		 */
173 		pipe->urb_alloc++;
174 
175 		usb_hif_free_urb_to_pipe(pipe, urb_context);
176 	}
177 
178 	HIF_DBG("athusb: alloc resources lpipe:%d hpipe:0x%X urbs:%d",
179 		pipe->logical_pipe_num,
180 		pipe->usb_pipe_handle,
181 		pipe->urb_alloc);
182 	return status;
183 }
184 
185 /**
186  * usb_hif_free_pipe_resources() - free urb resources allocated to a HIF pipe
187  * @pipe: pointer to struct HIF_USB_PIPE
188  *
189  * Return: none
190  */
191 static void usb_hif_free_pipe_resources(struct HIF_USB_PIPE *pipe)
192 {
193 	struct HIF_URB_CONTEXT *urb_context;
194 
195 	if (NULL == pipe->device) {
196 		/* nothing allocated for this pipe */
197 		HIF_ERROR("pipe->device is null");
198 		return;
199 	}
200 
201 	HIF_TRACE("athusb: free resources lpipe:%d hpipe:0x%X urbs:%d avail:%d",
202 			 pipe->logical_pipe_num,
203 			 pipe->usb_pipe_handle, pipe->urb_alloc,
204 			 pipe->urb_cnt);
205 
206 	if (pipe->urb_alloc != pipe->urb_cnt) {
207 		HIF_ERROR("athusb: urb leak! lpipe:%d hpipe:0x%X urbs:%d avail:%d",
208 				 pipe->logical_pipe_num,
209 				 pipe->usb_pipe_handle, pipe->urb_alloc,
210 				 pipe->urb_cnt);
211 	}
212 
213 	while (true) {
214 		urb_context = usb_hif_alloc_urb_from_pipe(pipe);
215 		if (NULL == urb_context)
216 			break;
217 
218 		if (urb_context->buf) {
219 			qdf_nbuf_free(urb_context->buf);
220 			urb_context->buf = NULL;
221 		}
222 
223 		usb_free_urb(urb_context->urb);
224 		urb_context->urb = NULL;
225 		qdf_mem_free(urb_context);
226 	}
227 
228 }
229 
230 /**
231  * usb_hif_get_logical_pipe_num() - get pipe number for a particular enpoint
232  * @device: pointer to HIF_DEVICE_USB structure
233  * @ep_address: endpoint address
234  * @urb_count: number of urb resources to be allocated to the pipe
235  *
236  * Return: uint8_t pipe number corresponding to ep_address
237  */
238 static uint8_t usb_hif_get_logical_pipe_num
239 					(struct HIF_DEVICE_USB *device,
240 					uint8_t ep_address,
241 					int *urb_count)
242 {
243 	uint8_t pipe_num = HIF_USB_PIPE_INVALID;
244 
245 	switch (ep_address) {
246 	case USB_EP_ADDR_APP_CTRL_IN:
247 		pipe_num = HIF_RX_CTRL_PIPE;
248 		*urb_count = RX_URB_COUNT;
249 		break;
250 	case USB_EP_ADDR_APP_DATA_IN:
251 		pipe_num = HIF_RX_DATA_PIPE;
252 		*urb_count = RX_URB_COUNT;
253 		break;
254 	case USB_EP_ADDR_APP_INT_IN:
255 		pipe_num = HIF_RX_INT_PIPE;
256 		*urb_count = RX_URB_COUNT;
257 		break;
258 	case USB_EP_ADDR_APP_DATA2_IN:
259 		pipe_num = HIF_RX_DATA2_PIPE;
260 		*urb_count = RX_URB_COUNT;
261 		break;
262 	case USB_EP_ADDR_APP_CTRL_OUT:
263 		pipe_num = HIF_TX_CTRL_PIPE;
264 		*urb_count = TX_URB_COUNT;
265 		break;
266 	case USB_EP_ADDR_APP_DATA_LP_OUT:
267 		pipe_num = HIF_TX_DATA_LP_PIPE;
268 		*urb_count = TX_URB_COUNT;
269 		break;
270 	case USB_EP_ADDR_APP_DATA_MP_OUT:
271 		pipe_num = HIF_TX_DATA_MP_PIPE;
272 		*urb_count = TX_URB_COUNT;
273 		break;
274 	case USB_EP_ADDR_APP_DATA_HP_OUT:
275 		pipe_num = HIF_TX_DATA_HP_PIPE;
276 		*urb_count = TX_URB_COUNT;
277 		break;
278 	default:
279 		/* note: there may be endpoints not currently used */
280 		break;
281 	}
282 
283 	return pipe_num;
284 }
285 
286 /**
287  * usb_hif_get_logical_pipe_num() - setup urb resources for all pipes
288  * @device: pointer to HIF_DEVICE_USB structure
289  *
290  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
291  */
292 QDF_STATUS usb_hif_setup_pipe_resources(struct HIF_DEVICE_USB *device)
293 {
294 	struct usb_interface *interface = device->interface;
295 	struct usb_host_interface *iface_desc = interface->cur_altsetting;
296 	struct usb_endpoint_descriptor *endpoint;
297 	int i;
298 	int urbcount;
299 	QDF_STATUS status = QDF_STATUS_SUCCESS;
300 	struct HIF_USB_PIPE *pipe;
301 	uint8_t pipe_num;
302 
303 	/* walk decriptors and setup pipes */
304 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
305 		endpoint = &iface_desc->endpoint[i].desc;
306 
307 		if (IS_BULK_EP(endpoint->bmAttributes)) {
308 			HIF_DBG("%s Bulk Ep:0x%2.2X maxpktsz:%d",
309 				IS_DIR_IN(endpoint->bEndpointAddress) ?
310 								"RX" : "TX",
311 				endpoint->bEndpointAddress,
312 				qdf_le16_to_cpu(endpoint->wMaxPacketSize));
313 		} else if (IS_INT_EP(endpoint->bmAttributes)) {
314 			HIF_DBG("%s Int Ep:0x%2.2X maxpktsz:%d interval:%d",
315 				IS_DIR_IN(endpoint->bEndpointAddress) ?
316 								"RX" : "TX",
317 				endpoint->bEndpointAddress,
318 				qdf_le16_to_cpu(endpoint->wMaxPacketSize),
319 				endpoint->bInterval);
320 		} else if (IS_ISOC_EP(endpoint->bmAttributes)) {
321 			/* TODO for ISO */
322 			HIF_DBG("%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d",
323 				IS_DIR_IN(endpoint->bEndpointAddress) ?
324 								"RX" : "TX",
325 				endpoint->bEndpointAddress,
326 				qdf_le16_to_cpu(endpoint->wMaxPacketSize),
327 				endpoint->bInterval);
328 		}
329 		urbcount = 0;
330 
331 		pipe_num = usb_hif_get_logical_pipe_num(device,
332 						endpoint->bEndpointAddress,
333 						&urbcount);
334 		if (HIF_USB_PIPE_INVALID == pipe_num)
335 			continue;
336 
337 		pipe = &device->pipes[pipe_num];
338 		if (pipe->device != NULL) {
339 			/*pipe was already setup */
340 			continue;
341 		}
342 
343 		pipe->device = device;
344 		pipe->logical_pipe_num = pipe_num;
345 		pipe->ep_address = endpoint->bEndpointAddress;
346 		pipe->max_packet_size =
347 			qdf_le16_to_cpu(endpoint->wMaxPacketSize);
348 
349 		if (IS_BULK_EP(endpoint->bmAttributes)) {
350 			if (IS_DIR_IN(pipe->ep_address)) {
351 				pipe->usb_pipe_handle =
352 					usb_rcvbulkpipe(device->udev,
353 							pipe->ep_address);
354 			} else {
355 				pipe->usb_pipe_handle =
356 					usb_sndbulkpipe(device->udev,
357 						pipe->ep_address);
358 			}
359 		} else if (IS_INT_EP(endpoint->bmAttributes)) {
360 			if (IS_DIR_IN(pipe->ep_address)) {
361 				pipe->usb_pipe_handle =
362 					usb_rcvintpipe(device->udev,
363 						pipe->ep_address);
364 			} else {
365 				pipe->usb_pipe_handle =
366 					usb_sndintpipe(device->udev,
367 						pipe->ep_address);
368 			}
369 		} else if (IS_ISOC_EP(endpoint->bmAttributes)) {
370 			/* TODO for ISO */
371 			if (IS_DIR_IN(pipe->ep_address)) {
372 				pipe->usb_pipe_handle =
373 					usb_rcvisocpipe(device->udev,
374 						pipe->ep_address);
375 			} else {
376 				pipe->usb_pipe_handle =
377 					usb_sndisocpipe(device->udev,
378 						pipe->ep_address);
379 			}
380 		}
381 		pipe->ep_desc = endpoint;
382 
383 		if (!IS_DIR_IN(pipe->ep_address))
384 			pipe->flags |= HIF_USB_PIPE_FLAG_TX;
385 
386 		status = usb_hif_alloc_pipe_resources(pipe, urbcount);
387 
388 		if (!QDF_IS_STATUS_SUCCESS(status))
389 			break;
390 
391 	}
392 
393 	return status;
394 }
395 
396 
397 /**
398  * usb_hif_cleanup_pipe_resources() - free urb resources for all pipes
399  * @device: pointer to HIF_DEVICE_USB structure
400  *
401  * Return: none
402  */
403 void usb_hif_cleanup_pipe_resources(struct HIF_DEVICE_USB *device)
404 {
405 	int i;
406 
407 	for (i = 0; i < HIF_USB_PIPE_MAX; i++)
408 		usb_hif_free_pipe_resources(&device->pipes[i]);
409 }
410 
411 /**
412  * usb_hif_flush_pending_transfers() - kill pending urbs for a pipe
413  * @pipe: pointer to struct HIF_USB_PIPE structure
414  *
415  * Return: none
416  */
417 static void usb_hif_flush_pending_transfers(struct HIF_USB_PIPE *pipe)
418 {
419 	struct HIF_URB_CONTEXT *urb_context;
420 
421 	HIF_TRACE("+%s pipe : %d", __func__, pipe->logical_pipe_num);
422 
423 	while (1) {
424 		urb_context = usb_hif_dequeue_pending_transfer(pipe);
425 		if (NULL == urb_context) {
426 			HIF_WARN("urb_context is NULL");
427 			break;
428 		}
429 		HIF_TRACE("  pending urb ctxt: 0x%pK", urb_context);
430 		if (urb_context->urb != NULL) {
431 			HIF_TRACE("  killing urb: 0x%pK", urb_context->urb);
432 			/* killing the URB will cause the completion routines to
433 			 * run
434 			 */
435 			usb_kill_urb(urb_context->urb);
436 		}
437 	}
438 	HIF_TRACE("-%s", __func__);
439 }
440 
441 /**
442  * usb_hif_flush_all() - flush pending transfers for all pipes for a usb bus
443  * @device: pointer to HIF_DEVICE_USB structure
444  *
445  * Return: none
446  */
447 void usb_hif_flush_all(struct HIF_DEVICE_USB *device)
448 {
449 	int i;
450 	struct HIF_USB_PIPE *pipe;
451 
452 	HIF_TRACE("+%s", __func__);
453 
454 	for (i = 0; i < HIF_USB_PIPE_MAX; i++) {
455 		if (device->pipes[i].device != NULL) {
456 			usb_hif_flush_pending_transfers(&device->pipes[i]);
457 			pipe = &device->pipes[i];
458 
459 		HIF_USB_FLUSH_WORK(pipe);
460 		}
461 	}
462 
463 	HIF_TRACE("-%s", __func__);
464 }
465 
466 /**
467  * usb_hif_cleanup_recv_urb() - cleanup recv urb
468  * @urb_context: pointer to struct HIF_URB_CONTEXT structure
469  *
470  * Return: none
471  */
472 static void usb_hif_cleanup_recv_urb(struct HIF_URB_CONTEXT *urb_context)
473 {
474 	HIF_TRACE("+%s", __func__);
475 
476 	if (urb_context->buf != NULL) {
477 		qdf_nbuf_free(urb_context->buf);
478 		urb_context->buf = NULL;
479 	}
480 
481 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
482 	HIF_TRACE("-%s", __func__);
483 }
484 
485 /**
486  * usb_hif_cleanup_transmit_urb() - cleanup transmit urb
487  * @urb_context: pointer to struct HIF_URB_CONTEXT structure
488  *
489  * Return: none
490  */
491 void usb_hif_cleanup_transmit_urb(struct HIF_URB_CONTEXT *urb_context)
492 {
493 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
494 }
495 
496 /**
497  * usb_hif_usb_recv_prestart_complete() - completion routine for prestart rx urb
498  * @urb: urb for which the completion routine is being called
499  *
500  * Return: none
501  */
502 static void usb_hif_usb_recv_prestart_complete
503 							(struct urb *urb)
504 {
505 	struct HIF_URB_CONTEXT *urb_context =
506 					(struct HIF_URB_CONTEXT *) urb->context;
507 	QDF_STATUS status = QDF_STATUS_SUCCESS;
508 	qdf_nbuf_t buf = NULL;
509 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
510 
511 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
512 		__func__,
513 		pipe->logical_pipe_num,
514 		urb->status, urb->actual_length,
515 		urb);
516 
517 	/* this urb is not pending anymore */
518 	usb_hif_remove_pending_transfer(urb_context);
519 	do {
520 		if (urb->status != 0) {
521 			status = A_ECOMM;
522 			switch (urb->status) {
523 			case -ECONNRESET:
524 			case -ENOENT:
525 			case -ESHUTDOWN:
526 				/* NOTE: no need to spew these errors when
527 				 * device is removed
528 				 * or urb is killed due to driver shutdown
529 				 */
530 				status = A_ECANCELED;
531 				break;
532 			default:
533 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
534 					__func__,
535 					pipe->logical_pipe_num,
536 					pipe->ep_address,
537 					urb->status);
538 				break;
539 			}
540 			break;
541 		}
542 		if (urb->actual_length == 0)
543 			break;
544 		buf = urb_context->buf;
545 		/* we are going to pass it up */
546 		urb_context->buf = NULL;
547 		qdf_nbuf_put_tail(buf, urb->actual_length);
548 
549 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
550 			uint8_t *data;
551 			uint32_t len;
552 
553 			qdf_nbuf_peek_header(buf, &data, &len);
554 			debug_dump_bytes(data, len, "hif recv data");
555 		}
556 		/* note: queue implements a lock */
557 		skb_queue_tail(&pipe->io_comp_queue, buf);
558 
559 		HIF_USB_SCHEDULE_WORK(pipe);
560 	} while (false);
561 
562 	usb_hif_cleanup_recv_urb(urb_context);
563 
564 	/* Prestart URBs runs out and now start working receive pipe. */
565 	if (--pipe->urb_prestart_cnt == 0)
566 		usb_hif_start_recv_pipes(pipe->device);
567 
568 	HIF_DBG("-%s", __func__);
569 }
570 
571 /**
572  * usb_hif_usb_recv_complete() - completion routine for rx urb
573  * @urb: urb for which the completion routine is being called
574  *
575  * Return: none
576  */
577 static void usb_hif_usb_recv_complete(struct urb *urb)
578 {
579 	struct HIF_URB_CONTEXT *urb_context =
580 					(struct HIF_URB_CONTEXT *) urb->context;
581 	QDF_STATUS status = QDF_STATUS_SUCCESS;
582 	qdf_nbuf_t buf = NULL;
583 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
584 	struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
585 
586 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
587 		__func__,
588 		pipe->logical_pipe_num,
589 		urb->status, urb->actual_length,
590 		urb);
591 
592 	/* this urb is not pending anymore */
593 	usb_hif_remove_pending_transfer(urb_context);
594 
595 	do {
596 
597 		if (urb->status != 0) {
598 			status = A_ECOMM;
599 			switch (urb->status) {
600 #ifdef RX_SG_SUPPORT
601 			case -EOVERFLOW:
602 				urb->actual_length = HIF_USB_RX_BUFFER_SIZE;
603 				status = QDF_STATUS_SUCCESS;
604 				break;
605 #endif
606 			case -ECONNRESET:
607 			case -ENOENT:
608 			case -ESHUTDOWN:
609 				/* NOTE: no need to spew these errors when
610 				 * device is removed
611 				 * or urb is killed due to driver shutdown
612 				 */
613 				status = A_ECANCELED;
614 				break;
615 			default:
616 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
617 					__func__,
618 					pipe->logical_pipe_num,
619 					pipe->ep_address,
620 					urb->status);
621 				break;
622 			}
623 			break;
624 		}
625 		if (urb->actual_length == 0)
626 			break;
627 		buf = urb_context->buf;
628 		/* we are going to pass it up */
629 		urb_context->buf = NULL;
630 		qdf_nbuf_put_tail(buf, urb->actual_length);
631 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
632 			uint8_t *data;
633 			uint32_t len;
634 
635 			qdf_nbuf_peek_header(buf, &data, &len);
636 			debug_dump_bytes(data, len, "hif recv data");
637 		}
638 		/* note: queue implements a lock */
639 		skb_queue_tail(&pipe->io_comp_queue, buf);
640 		HIF_USB_SCHEDULE_WORK(pipe);
641 	} while (false);
642 
643 	usb_hif_cleanup_recv_urb(urb_context);
644 
645 	/* Only re-submit URB when STATUS is success and HIF is not at the
646 	 * suspend state.
647 	 */
648 	if (QDF_IS_STATUS_SUCCESS(status) && !sc->suspend_state) {
649 		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
650 			/* our free urbs are piling up, post more transfers */
651 			usb_hif_post_recv_transfers(pipe,
652 						HIF_USB_RX_BUFFER_SIZE);
653 		}
654 	} else {
655 		HIF_ERROR("%s:  pipe: %d, fail to post URB: status(%d) suspend (%d)",
656 				__func__,
657 				pipe->logical_pipe_num,
658 				urb->status,
659 				sc->suspend_state);
660 	}
661 
662 	HIF_DBG("-%s", __func__);
663 }
664 
665 /**
666  * usb_hif_usb_recv_bundle_complete() - completion routine for rx bundling urb
667  * @urb: urb for which the completion routine is being called
668  *
669  * Return: none
670  */
671 static void usb_hif_usb_recv_bundle_complete(struct urb *urb)
672 {
673 	struct HIF_URB_CONTEXT *urb_context =
674 					(struct HIF_URB_CONTEXT *) urb->context;
675 	QDF_STATUS status = QDF_STATUS_SUCCESS;
676 	qdf_nbuf_t buf = NULL;
677 	struct HIF_USB_PIPE *pipe = urb_context->pipe;
678 	uint8_t *netdata, *netdata_new;
679 	uint32_t netlen, netlen_new;
680 	HTC_FRAME_HDR *HtcHdr;
681 	uint16_t payloadLen;
682 	qdf_nbuf_t new_skb = NULL;
683 
684 	HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%pK",
685 		__func__,
686 		pipe->logical_pipe_num,
687 		urb->status, urb->actual_length,
688 		urb);
689 
690 	/* this urb is not pending anymore */
691 	usb_hif_remove_pending_transfer(urb_context);
692 
693 	do {
694 
695 		if (urb->status != 0) {
696 			status = A_ECOMM;
697 			switch (urb->status) {
698 			case -ECONNRESET:
699 			case -ENOENT:
700 			case -ESHUTDOWN:
701 				/* NOTE: no need to spew these errors when
702 				 * device is removed
703 				 * or urb is killed due to driver shutdown
704 				 */
705 				status = A_ECANCELED;
706 				break;
707 			default:
708 				HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d",
709 					__func__,
710 					pipe->logical_pipe_num,
711 					pipe->ep_address,
712 					urb->status);
713 				break;
714 			}
715 			break;
716 		}
717 		if (urb->actual_length == 0)
718 			break;
719 		buf = urb_context->buf;
720 		if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) {
721 			uint8_t *data;
722 			uint32_t len;
723 
724 			qdf_nbuf_peek_header(buf, &data, &len);
725 			debug_dump_bytes(data, len, "hif recv data");
726 		}
727 
728 		qdf_nbuf_peek_header(buf, &netdata, &netlen);
729 		netlen = urb->actual_length;
730 
731 		do {
732 			uint16_t frame_len;
733 
734 			if (IS_FW_CRASH_DUMP(*(uint32_t *) netdata))
735 				frame_len = netlen;
736 			else {
737 				/* Hack into HTC header for bundle processing */
738 				HtcHdr = (HTC_FRAME_HDR *) netdata;
739 				if (HtcHdr->EndpointID >= ENDPOINT_MAX) {
740 					HIF_ERROR("athusb: Rx: invalid EndpointID=%d",
741 						HtcHdr->EndpointID);
742 					break;
743 				}
744 
745 				payloadLen = HtcHdr->PayloadLen;
746 				payloadLen = qdf_le16_to_cpu(payloadLen);
747 
748 				if (payloadLen > HIF_USB_RX_BUFFER_SIZE) {
749 					HIF_ERROR("athusb: payloadLen too long %u",
750 						payloadLen);
751 					break;
752 				}
753 				frame_len = (HTC_HDR_LENGTH + payloadLen);
754 			}
755 
756 			if (netlen < frame_len) {
757 				HIF_ERROR("athusb: subframe length %d not fitted into bundle packet length %d"
758 					, netlen, frame_len);
759 				break;
760 			}
761 
762 			/* allocate a new skb and copy */
763 			new_skb =
764 				qdf_nbuf_alloc(NULL, frame_len, 0, 4, false);
765 			if (new_skb == NULL) {
766 				HIF_ERROR("athusb: allocate skb (len=%u) failed"
767 						, frame_len);
768 				break;
769 			}
770 
771 			qdf_nbuf_peek_header(new_skb, &netdata_new,
772 						&netlen_new);
773 			qdf_mem_copy(netdata_new, netdata, frame_len);
774 			qdf_nbuf_put_tail(new_skb, frame_len);
775 			skb_queue_tail(&pipe->io_comp_queue, new_skb);
776 			new_skb = NULL;
777 			netdata += frame_len;
778 			netlen -= frame_len;
779 		} while (netlen);
780 		HIF_USB_SCHEDULE_WORK(pipe);
781 	} while (false);
782 
783 	if (urb_context->buf == NULL)
784 		HIF_ERROR("athusb: buffer in urb_context is NULL");
785 
786 	/* reset urb_context->buf ==> seems not necessary */
787 	usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context);
788 
789 	if (QDF_IS_STATUS_SUCCESS(status)) {
790 		if (pipe->urb_cnt >= pipe->urb_cnt_thresh) {
791 			/* our free urbs are piling up, post more transfers */
792 			usb_hif_post_recv_bundle_transfers(pipe,
793 					pipe->device->rx_bundle_buf_len);
794 		}
795 	}
796 
797 	HIF_DBG("-%s", __func__);
798 }
799 
800 /**
801  * usb_hif_post_recv_prestart_transfers() - post prestart recv urbs for a pipe
802  * @recv_pipe: rx data pipe
803  * @prestart_urb: number of prestart recv urbs to be posted
804  *
805  * Return: none
806  */
807 static void usb_hif_post_recv_prestart_transfers(struct HIF_USB_PIPE *recv_pipe,
808 						int prestart_urb)
809 {
810 	struct HIF_URB_CONTEXT *urb_context;
811 	uint8_t *data;
812 	uint32_t len;
813 	struct urb *urb;
814 	int i, usb_status, buffer_length = HIF_USB_RX_BUFFER_SIZE;
815 
816 	HIF_TRACE("+%s", __func__);
817 
818 	for (i = 0; i < prestart_urb; i++) {
819 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
820 		if (NULL == urb_context)
821 			break;
822 
823 		urb_context->buf =
824 			qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
825 		if (NULL == urb_context->buf) {
826 			usb_hif_cleanup_recv_urb(urb_context);
827 			break;
828 		}
829 
830 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
831 
832 		urb = urb_context->urb;
833 
834 		usb_fill_bulk_urb(urb,
835 				recv_pipe->device->udev,
836 				recv_pipe->usb_pipe_handle,
837 				data,
838 				buffer_length,
839 				usb_hif_usb_recv_prestart_complete,
840 				urb_context);
841 
842 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
843 			recv_pipe->logical_pipe_num,
844 			recv_pipe->usb_pipe_handle,
845 			recv_pipe->ep_address, buffer_length,
846 			urb_context->buf);
847 
848 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
849 
850 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
851 
852 		if (usb_status) {
853 			HIF_ERROR("athusb : usb bulk recv failed %d",
854 				usb_status);
855 			usb_hif_remove_pending_transfer(urb_context);
856 			usb_hif_cleanup_recv_urb(urb_context);
857 			break;
858 		}
859 		recv_pipe->urb_prestart_cnt++;
860 	}
861 
862 	HIF_TRACE("-%s", __func__);
863 }
864 
865 /**
866  * usb_hif_post_recv_transfers() - post recv urbs for a given pipe
867  * @recv_pipe: recv pipe for which urbs need to be posted
868  * @buffer_length: buffer length of the recv urbs
869  *
870  * Return: none
871  */
872 static void usb_hif_post_recv_transfers(struct HIF_USB_PIPE *recv_pipe,
873 							int buffer_length)
874 {
875 	struct HIF_URB_CONTEXT *urb_context;
876 	uint8_t *data;
877 	uint32_t len;
878 	struct urb *urb;
879 	int usb_status;
880 
881 	HIF_TRACE("+%s", __func__);
882 
883 	while (1) {
884 
885 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
886 		if (NULL == urb_context)
887 			break;
888 
889 		urb_context->buf = qdf_nbuf_alloc(NULL, buffer_length, 0,
890 						4, false);
891 		if (NULL == urb_context->buf) {
892 			usb_hif_cleanup_recv_urb(urb_context);
893 			break;
894 		}
895 
896 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
897 
898 		urb = urb_context->urb;
899 
900 		usb_fill_bulk_urb(urb,
901 				recv_pipe->device->udev,
902 				recv_pipe->usb_pipe_handle,
903 				data,
904 				buffer_length,
905 				usb_hif_usb_recv_complete, urb_context);
906 
907 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
908 			recv_pipe->logical_pipe_num,
909 			recv_pipe->usb_pipe_handle,
910 			recv_pipe->ep_address, buffer_length,
911 			urb_context->buf);
912 
913 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
914 
915 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
916 
917 		if (usb_status) {
918 			HIF_ERROR("athusb : usb bulk recv failed %d",
919 				usb_status);
920 			usb_hif_remove_pending_transfer(urb_context);
921 			usb_hif_cleanup_recv_urb(urb_context);
922 			break;
923 		}
924 	}
925 
926 	HIF_TRACE("-%s", __func__);
927 
928 }
929 
930 /**
931  * usb_hif_post_recv_bundle_transfers() - post recv urbs for a given pipe
932  * @recv_pipe: recv pipe for which urbs need to be posted
933  * @buffer_length: maximum length of rx bundle
934  *
935  * Return: none
936  */
937 static void usb_hif_post_recv_bundle_transfers(struct HIF_USB_PIPE *recv_pipe,
938 						int buffer_length)
939 {
940 	struct HIF_URB_CONTEXT *urb_context;
941 	uint8_t *data;
942 	uint32_t len;
943 	struct urb *urb;
944 	int usb_status;
945 
946 	HIF_TRACE("+%s", __func__);
947 
948 	while (1) {
949 
950 		urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe);
951 		if (NULL == urb_context)
952 			break;
953 
954 		if (NULL == urb_context->buf) {
955 			urb_context->buf =
956 			qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false);
957 			if (NULL == urb_context->buf) {
958 				usb_hif_cleanup_recv_urb(urb_context);
959 				break;
960 			}
961 		}
962 
963 		qdf_nbuf_peek_header(urb_context->buf, &data, &len);
964 
965 		urb = urb_context->urb;
966 		usb_fill_bulk_urb(urb,
967 				recv_pipe->device->udev,
968 				recv_pipe->usb_pipe_handle,
969 				data,
970 				buffer_length,
971 				usb_hif_usb_recv_bundle_complete,
972 				urb_context);
973 
974 		HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%pK",
975 			recv_pipe->logical_pipe_num,
976 			recv_pipe->usb_pipe_handle,
977 			recv_pipe->ep_address, buffer_length,
978 			urb_context->buf);
979 
980 		usb_hif_enqueue_pending_transfer(recv_pipe, urb_context);
981 
982 		usb_status = usb_submit_urb(urb, GFP_ATOMIC);
983 
984 		if (usb_status) {
985 			HIF_ERROR("athusb : usb bulk recv failed %d",
986 				usb_status);
987 			usb_hif_remove_pending_transfer(urb_context);
988 			usb_hif_free_urb_to_pipe(urb_context->pipe,
989 						urb_context);
990 			break;
991 		}
992 
993 	}
994 
995 	HIF_TRACE("-%s", __func__);
996 
997 }
998 
999 /**
1000  * usb_hif_prestart_recv_pipes() - post prestart recv urbs
1001  * @device: HIF device for which prestart recv urbs need to be posted
1002  *
1003  * Return: none
1004  */
1005 void usb_hif_prestart_recv_pipes(struct HIF_DEVICE_USB *device)
1006 {
1007 	struct HIF_USB_PIPE *pipe = &device->pipes[HIF_RX_DATA_PIPE];
1008 
1009 	/*
1010 	 * USB driver learn to support bundle or not until the firmware
1011 	 * download and ready. Only allocate some URBs for control message
1012 	 * communication during the initial phase then start the final
1013 	 * working pipe after all information understood.
1014 	 */
1015 	usb_hif_post_recv_prestart_transfers(pipe, 8);
1016 }
1017 
1018 /**
1019  * usb_hif_start_recv_pipes() - start recv urbs
1020  * @device: HIF device for which recv urbs need to be posted
1021  *
1022  * This function is called after all prestart recv urbs are exhausted
1023  *
1024  * Return: none
1025  */
1026 void usb_hif_start_recv_pipes(struct HIF_DEVICE_USB *device)
1027 {
1028 	struct HIF_USB_PIPE *pipe;
1029 	uint32_t buf_len;
1030 
1031 	HIF_ENTER();
1032 	pipe = &device->pipes[HIF_RX_DATA_PIPE];
1033 	pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1034 
1035 	HIF_TRACE("Post URBs to RX_DATA_PIPE: %d",
1036 		device->pipes[HIF_RX_DATA_PIPE].urb_cnt);
1037 	if (device->is_bundle_enabled) {
1038 		usb_hif_post_recv_bundle_transfers(pipe,
1039 					pipe->device->rx_bundle_buf_len);
1040 	} else {
1041 		buf_len = HIF_USB_RX_BUFFER_SIZE;
1042 		usb_hif_post_recv_transfers(pipe, buf_len);
1043 	}
1044 
1045 	HIF_DBG("athusb bulk recv len %d", buf_len);
1046 
1047 	if (!hif_usb_disable_rxdata2) {
1048 		HIF_TRACE("Post URBs to RX_DATA2_PIPE: %d",
1049 			device->pipes[HIF_RX_DATA2_PIPE].urb_cnt);
1050 
1051 		pipe = &device->pipes[HIF_RX_DATA2_PIPE];
1052 		pipe->urb_cnt_thresh = pipe->urb_alloc / 2;
1053 		usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE);
1054 	}
1055 
1056 	HIF_EXIT();
1057 }
1058 
1059 /**
1060  * usb_hif_submit_ctrl_out() - send out a ctrl urb
1061  * @device: HIF device for which urb needs to be posted
1062  * @req: request value for the ctrl message
1063  * @value: USB message value
1064  * @index: USB message index value
1065  * @data: pointer to data containing ctrl message to send
1066  * @size: size of the control message to send
1067  *
1068  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1069  */
1070 QDF_STATUS usb_hif_submit_ctrl_out(struct HIF_DEVICE_USB *device,
1071 				   uint8_t req, uint16_t value, uint16_t index,
1072 				   void *data, uint32_t size)
1073 {
1074 	int32_t result = 0;
1075 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1076 	uint8_t *buf = NULL;
1077 
1078 	do {
1079 
1080 		if (size > 0) {
1081 			buf = qdf_mem_malloc(size);
1082 			if (NULL == buf) {
1083 				ret = QDF_STATUS_E_NOMEM;
1084 				break;
1085 			}
1086 			qdf_mem_copy(buf, (uint8_t *) data, size);
1087 		}
1088 
1089 		HIF_DBG("ctrl-out req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1090 				req, value, index, size);
1091 
1092 		result = usb_control_msg(device->udev,
1093 					usb_sndctrlpipe(device->udev, 0),
1094 					req,
1095 					USB_DIR_OUT | USB_TYPE_VENDOR |
1096 					USB_RECIP_DEVICE, value, index, buf,
1097 					size, 2 * HZ);
1098 
1099 		if (result < 0) {
1100 			HIF_ERROR("%s failed,result = %d", __func__, result);
1101 			ret = QDF_STATUS_E_FAILURE;
1102 		}
1103 
1104 	} while (false);
1105 
1106 	if (buf != NULL)
1107 		qdf_mem_free(buf);
1108 
1109 	return ret;
1110 }
1111 
1112 /**
1113  * usb_hif_submit_ctrl_in() - recv a resonse to the ctrl message sent out
1114  * @device: HIF device for which urb needs to be received
1115  * @req: request value for the ctrl message
1116  * @value: USB message value
1117  * @index: USB message index value
1118  * @data: pointer to data containing ctrl message to be received
1119  * @size: size of the control message to be received
1120  *
1121  * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error
1122  */
1123 QDF_STATUS usb_hif_submit_ctrl_in(struct HIF_DEVICE_USB *device,
1124 				  uint8_t req, uint16_t value, uint16_t index,
1125 				  void *data, uint32_t size)
1126 {
1127 	int32_t result = 0;
1128 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
1129 	uint8_t *buf = NULL;
1130 
1131 	do {
1132 
1133 		if (size > 0) {
1134 			buf = qdf_mem_malloc(size);
1135 			if (NULL == buf) {
1136 				ret = QDF_STATUS_E_NOMEM;
1137 				break;
1138 			}
1139 		}
1140 
1141 		HIF_DBG("ctrl-in req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d",
1142 				 req, value, index, size);
1143 
1144 		result = usb_control_msg(device->udev,
1145 					usb_rcvctrlpipe(device->udev, 0),
1146 					req,
1147 					USB_DIR_IN | USB_TYPE_VENDOR |
1148 					USB_RECIP_DEVICE, value, index, buf,
1149 					size, 2 * HZ);
1150 
1151 		if (result < 0) {
1152 			HIF_ERROR("%s failed, result = %d", __func__, result);
1153 			ret = QDF_STATUS_E_FAILURE;
1154 			break;
1155 		}
1156 
1157 		qdf_mem_copy((uint8_t *) data, buf, size);
1158 
1159 	} while (false);
1160 
1161 	if (buf != NULL)
1162 		qdf_mem_free(buf);
1163 
1164 	return ret;
1165 }
1166 
1167 /**
1168  * usb_hif_io_complete() - transmit call back for tx urb
1169  * @pipe: pointer to struct HIF_USB_PIPE
1170  *
1171  * Return: none
1172  */
1173 static void usb_hif_io_complete(struct HIF_USB_PIPE *pipe)
1174 {
1175 	qdf_nbuf_t buf;
1176 	struct HIF_DEVICE_USB *device;
1177 	HTC_FRAME_HDR *HtcHdr;
1178 	uint8_t *data;
1179 	uint32_t len;
1180 	struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device);
1181 
1182 	device = pipe->device;
1183 	HIF_ENTER();
1184 	while ((buf = skb_dequeue(&pipe->io_comp_queue))) {
1185 		if (pipe->flags & HIF_USB_PIPE_FLAG_TX) {
1186 			HIF_DBG("+athusb xmit callback buf:0x%pK", buf);
1187 			HtcHdr = (HTC_FRAME_HDR *)
1188 					qdf_nbuf_get_frag_vaddr(buf, 0);
1189 
1190 #ifdef ATH_11AC_TXCOMPACT
1191 /* ATH_11AC_TXCOMPACT does not support High Latency mode */
1192 #else
1193 			device->htc_callbacks.txCompletionHandler(device->
1194 								htc_callbacks.
1195 								Context, buf,
1196 								HtcHdr->
1197 								EndpointID, 0);
1198 #endif
1199 			HIF_DBG("-athusb xmit callback");
1200 		} else {
1201 			HIF_DBG("+athusb recv callback buf: 0x%pK", buf);
1202 			qdf_nbuf_peek_header(buf, &data, &len);
1203 
1204 			if (IS_FW_CRASH_DUMP(*((uint32_t *) data))) {
1205 				sc->fw_data = data;
1206 				sc->fw_data_len = len;
1207 				device->htc_callbacks.fwEventHandler(
1208 					device->htc_callbacks.Context,
1209 					QDF_STATUS_E_USB_ERROR);
1210 				qdf_nbuf_free(buf);
1211 			} else {
1212 				device->htc_callbacks.rxCompletionHandler(
1213 				device->htc_callbacks.Context, buf,
1214 				pipe->logical_pipe_num);
1215 			}
1216 			HIF_DBG("-athusb recv callback");
1217 		}
1218 	}
1219 
1220 	HIF_EXIT();
1221 }
1222 
1223 #ifdef HIF_USB_TASKLET
1224 /**
1225  * usb_hif_io_comp_tasklet() - per pipe tasklet routine
1226  * @context: pointer to HIF USB pipe
1227  *
1228  * Return: none
1229  */
1230 void usb_hif_io_comp_tasklet(unsigned long context)
1231 {
1232 	struct HIF_USB_PIPE *pipe = (struct HIF_USB_PIPE *) context;
1233 
1234 	usb_hif_io_complete(pipe);
1235 }
1236 
1237 #else
1238 /**
1239  * usb_hif_io_comp_work() - per pipe work queue
1240  * @work: pointer to struct work_struct
1241  *
1242  * Return: none
1243  */
1244 void usb_hif_io_comp_work(struct work_struct *work)
1245 {
1246 	struct HIF_USB_PIPE *pipe = container_of(work, struct HIF_USB_PIPE,
1247 						 io_complete_work);
1248 
1249 	usb_hif_io_complete(pipe);
1250 }
1251 #endif
1252