as3525v2-usb: don't disable interrupts on bus reset (that was for debug purpose)
[kugel-rb.git] / firmware / target / arm / as3525 / usb-drv-as3525v2.c
blobb570ddb6c8e5ea6b8f57c9c8d8c9ed18941922da
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright © 2010 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "usb.h"
23 #include "usb_drv.h"
24 #include "as3525v2.h"
25 #include "clock-target.h"
26 #include "ascodec.h"
27 #include "as3514.h"
28 #include "stdbool.h"
29 #include "string.h"
30 #include "stdio.h"
31 #include "panic.h"
32 #include "mmu-arm.h"
33 #include "system.h"
34 #define LOGF_ENABLE
35 #include "logf.h"
36 #include "usb-drv-as3525v2.h"
38 struct usb_endpoint
40 void *buf;
41 unsigned int len;
42 union
44 unsigned int sent;
45 unsigned int received;
47 bool wait;
48 bool busy;
51 #if 0
52 static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2];
53 #endif
54 static struct usb_ctrlrequest ep0_setup_pkt;
56 void usb_attach(void)
58 logf("usb: attach");
59 usb_enable(true);
62 static void usb_delay(void)
64 int i = 0;
65 while(i < 0x300)
66 i++;
69 static void as3525v2_connect(void)
71 logf("usb: init as3525v2");
72 /* 1) enable usb core clock */
73 CGU_PERI |= CGU_USB_CLOCK_ENABLE;
74 usb_delay();
75 /* 2) enable usb phy clock */
76 CGU_USB |= 0x20;
77 usb_delay();
78 /* 3) clear "stop pclk" */
79 USB_PCGCCTL &= ~0x1;
80 usb_delay();
81 /* 4) clear "power clamp" */
82 USB_PCGCCTL &= ~0x4;
83 usb_delay();
84 /* 5) clear "reset power down module" */
85 USB_PCGCCTL &= ~0x8;
86 usb_delay();
87 /* 6) set "power on program done" */
88 USB_DCTL |= USB_DCTL_pwronprgdone;
89 usb_delay();
90 /* 7) core soft reset */
91 USB_GRSTCTL |= USB_GRSTCTL_csftrst;
92 usb_delay();
93 /* 8) hclk soft reset */
94 USB_GRSTCTL |= USB_GRSTCTL_hsftrst;
95 usb_delay();
96 /* 9) flush and reset everything */
97 USB_GRSTCTL |= 0x3f;
98 usb_delay();
99 /* 10) force device mode*/
100 USB_GUSBCFG &= ~USB_GUSBCFG_force_host_mode;
101 USB_GUSBCFG |= USB_GUSBCFG_force_device_mode;
102 usb_delay();
103 /* 11) Do something that is probably CCU related but undocumented*/
104 CCU_USB_THINGY &= ~0x1000;
105 usb_delay();
106 CCU_USB_THINGY &= ~0x300000;
107 usb_delay();
108 /* 12) reset usb core parameters (dev addr, speed, ...) */
109 USB_DCFG = 0;
110 usb_delay();
113 static void usb_enable_common_interrupts(void)
115 /* Clear any pending otg interrupt */
116 USB_GOTGINT = 0xffffffff;
117 /* Clear any pending interrupt */
118 USB_GINTSTS = 0Xffffffff;
119 /* Enable interrupts */
120 USB_GINTMSK = USB_GINTMSK_otgintr
121 | USB_GINTMSK_conidstschng
122 | USB_GINTMSK_disconnect;
125 static void usb_enable_device_interrupts(void)
127 /* Disable all interrupts */
128 USB_GINTMSK = 0;
129 /* Clear any pending interrupt */
130 USB_GINTSTS = 0xffffffff;
131 /* Enable common interrupts */
132 usb_enable_common_interrupts();
133 /* Enable interrupts */
134 USB_GINTMSK |= USB_GINTMSK_usbreset
135 | USB_GINTMSK_enumdone
136 | USB_GINTMSK_inepintr
137 | USB_GINTMSK_outepintr;
140 static void usb_flush_tx_fifos(int nums)
142 unsigned int i = 0;
144 USB_GRSTCTL = (USB_GRSTCTL & (~USB_GRSTCTL_txfnum_bits))
145 | (nums << USB_GRSTCTL_txfnum_bit_pos)
146 | USB_GRSTCTL_txfflsh_flush;
147 while(USB_GRSTCTL & USB_GRSTCTL_txfflsh_flush && i < 0x300)
148 i++;
149 if(USB_GRSTCTL & USB_GRSTCTL_txfflsh_flush)
150 panicf("usb: hang of flush tx fifos (%x)", nums);
151 /* wait 3 phy clocks */
152 udelay(1);
155 static void usb_flush_rx_fifo(void)
157 unsigned int i = 0;
159 USB_GRSTCTL = USB_GRSTCTL_rxfflsh_flush;
160 while(USB_GRSTCTL & USB_GRSTCTL_rxfflsh_flush && i < 0x300)
161 i++;
162 if(USB_GRSTCTL & USB_GRSTCTL_rxfflsh_flush)
163 panicf("usb: hang of flush rx fifo");
164 /* wait 3 phy clocks */
165 udelay(1);
168 static void core_reset(void)
170 unsigned int i = 0;
171 /* Wait for AHB master IDLE state. */
172 while((USB_GRSTCTL & USB_GRSTCTL_ahbidle) == 0)
173 udelay(10);
174 /* Core Soft Reset */
175 USB_GRSTCTL |= USB_GRSTCTL_csftrst;
176 /* Waits for the hardware to clear reset bit */
177 while(USB_GRSTCTL & USB_GRSTCTL_csftrst && i < 0x300)
178 i++;
180 if(USB_GRSTCTL & USB_GRSTCTL_csftrst)
181 panicf("oops, usb core soft reset hang :(");
183 /* Wait for 3 PHY Clocks */
184 udelay(1);
187 static void core_dev_init(void)
189 unsigned int usb_num_in_ep = 0;
190 unsigned int usb_num_out_ep = 0;
191 unsigned int i;
192 /* Restart the phy clock */
193 USB_PCGCCTL = 0;
194 /* Set phy speed : high speed */
195 USB_DCFG = (USB_DCFG & (~USB_DCFG_devspd_bits)) | USB_DCFG_devspd_hs_phy_hs;
196 /* Set periodic frame interval */
197 USB_DCFG = (USB_DCFG & (~USB_DCFG_perfrint_bits)) | (USB_DCFG_FRAME_INTERVAL_80 << USB_DCFG_perfrint_bit_pos);
199 /* Check hardware capabilities */
200 if(USB_GHWCFG2_ARCH != USB_INT_DMA_ARCH)
201 panicf("usb: wrong architecture (%ld)", USB_GHWCFG2_ARCH);
202 if(USB_GHWCFG2_HS_PHY_TYPE != USB_PHY_TYPE_UTMI)
203 panicf("usb: wrong HS phy type (%ld)", USB_GHWCFG2_HS_PHY_TYPE);
204 if(USB_GHWCFG2_FS_PHY_TYPE != USB_PHY_TYPE_UNSUPPORTED)
205 panicf("usb: wrong FS phy type (%ld)", USB_GHWCFG2_FS_PHY_TYPE);
206 if(USB_GHWCFG4_UTMI_PHY_DATA_WIDTH != 0x2)
207 panicf("usb: wrong utmi data width (%ld)", USB_GHWCFG4_UTMI_PHY_DATA_WIDTH);
208 if(USB_GHWCFG4_DED_FIFO_EN != 1) /* it seems to be multiple tx fifo support */
209 panicf("usb: no multiple tx fifo");
211 logf("hwcfg1: %08lx", USB_GHWCFG1);
212 logf("hwcfg2: %08lx", USB_GHWCFG2);
213 logf("hwcfg3: %08lx", USB_GHWCFG3);
214 logf("hwcfg4: %08lx", USB_GHWCFG4);
216 logf("%ld endpoints", USB_GHWCFG2_NUM_EP);
217 usb_num_in_ep = 0;
218 usb_num_out_ep = 0;
219 for(i = 0; i < USB_GHWCFG2_NUM_EP; i++)
221 if(USB_GHWCFG1_IN_EP(i))
222 usb_num_in_ep++;
223 if(USB_GHWCFG1_OUT_EP(i))
224 usb_num_out_ep++;
225 logf(" EP%d: IN=%ld OUT=%ld", i, USB_GHWCFG1_IN_EP(i), USB_GHWCFG1_OUT_EP(i));
228 if(usb_num_in_ep != USB_GHWCFG4_NUM_IN_EP)
229 panicf("usb: num in ep mismatch(%d,%lu)", usb_num_in_ep, USB_GHWCFG4_NUM_IN_EP);
230 if(usb_num_in_ep != USB_NUM_IN_EP)
231 panicf("usb: num in ep static mismatch(%u,%u)", usb_num_in_ep, USB_NUM_IN_EP);
232 if(usb_num_out_ep != USB_NUM_OUT_EP)
233 panicf("usb: num out ep static mismatch(%u,%u)", usb_num_out_ep, USB_NUM_OUT_EP);
235 logf("%d in ep, %d out ep", usb_num_in_ep, usb_num_out_ep);
236 logf("initial:");
237 logf(" tot fifo sz: %lx", USB_GHWCFG3_DFIFO_LEN);
238 logf(" rx fifo: [%04x,+%4lx]", 0, USB_GRXFSIZ);
239 logf(" nptx fifo: [%04lx,+%4lx]", USB_GET_FIFOSIZE_START_ADR(USB_GNPTXFSIZ),
240 USB_GET_FIFOSIZE_DEPTH(USB_GNPTXFSIZ));
241 for(i = 1; i <= USB_NUM_IN_EP; i++)
243 logf(" dieptx fifo(%2u): [%04lx,+%4lx]", i,
244 USB_GET_FIFOSIZE_START_ADR(USB_DIEPTXFSIZ(i)),
245 USB_GET_FIFOSIZE_DEPTH(USB_DIEPTXFSIZ(i)));
248 /* flush the fifos */
249 usb_flush_tx_fifos(0x10); /* flush all */
250 usb_flush_rx_fifo();
252 /* flush learning queue */
253 USB_GRSTCTL = USB_GRSTCTL_intknqflsh;
255 /* Clear all pending device interrupts */
256 USB_DIEPMSK = 0;
257 USB_DOEPMSK = 0;
258 USB_DAINT = 0xffffffff;
259 USB_DAINTMSK = 0;
261 for(i = 0; i <= USB_NUM_IN_EP; i++)
263 /* disable endpoint if enabled */
264 if(USB_DIEPCTL(i) & USB_DEPCTL_epena)
265 USB_DIEPCTL(i) = USB_DEPCTL_epdis | USB_DEPCTL_snak;
266 else
267 USB_DIEPCTL(i) = 0;
269 USB_DIEPTSIZ(i) = 0;
270 USB_DIEPDMA(i) = 0;
271 USB_DIEPINT(i) = 0xff;
274 for(i = 0; i <= USB_NUM_OUT_EP; i++)
276 /* disable endpoint if enabled */
277 if(USB_DOEPCTL(i) & USB_DEPCTL_epena)
278 USB_DOEPCTL(i) = USB_DEPCTL_epdis | USB_DEPCTL_snak;
279 else
280 USB_DOEPCTL(i) = 0;
282 USB_DOEPTSIZ(i) = 0;
283 USB_DOEPDMA(i) = 0;
284 USB_DOEPINT(i) = 0xff;
287 /* fixme: threshold tweaking only takes place if we use multiple tx fifos it seems */
288 /* only dump them for now, leave threshold disabled */
289 logf("threshold control:");
290 logf(" non_iso_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_non_iso_thr_en) ? 1 : 0);
291 logf(" iso_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_iso_thr_en) ? 1 : 0);
292 logf(" tx_thr_len: %lu", (USB_DTHRCTL & USB_DTHRCTL_tx_thr_len_bits) >> USB_DTHRCTL_tx_thr_len_bit_pos);
293 logf(" rx_thr_en: %d", (USB_DTHRCTL & USB_DTHRCTL_rx_thr_en) ? 1 : 0);
294 logf(" rx_thr_len: %lu", (USB_DTHRCTL & USB_DTHRCTL_rx_thr_len_bits) >> USB_DTHRCTL_rx_thr_len_bit_pos);
296 /* enable USB interrupts */
297 usb_enable_device_interrupts();
299 /* enable fifo underrun interrupt ? */
300 USB_DIEPMSK |= USB_DIEPINT_txfifoundrn;
303 static void core_init(void)
305 /* Setup phy for high speed */
306 USB_GUSBCFG &= ~USB_GUSBCFG_ulpi_ext_vbus_drv;
307 /* Disable external TS Dline pulsing (???) */
308 USB_GUSBCFG &= ~USB_GUSBCFG_term_sel_dl_pulse;
309 /* core reset */
310 core_reset();
312 /* Select UTMI */
313 USB_GUSBCFG &= ~USB_GUSBCFG_ulpi_utmi_sel;
314 /* Select UTMI+ 16 */
315 USB_GUSBCFG |= USB_GUSBCFG_phy_if;
316 /* core reset */
317 core_reset();
319 /* fixme: the linux code does that but the clip+ doesn't use ULPI it seems */
320 USB_GUSBCFG &= ~(USB_GUSBCFG_ulpi_fsls | USB_GUSBCFG_ulpi_clk_sus_m);
322 /* fixme: the current code is for internal DMA only, the clip+ architecture
323 * define the internal DMA model */
324 /* Set burstlen and enable DMA*/
325 USB_GAHBCFG = (USB_GAHBCFG_INT_DMA_BURST_INCR << USB_GAHBCFG_hburstlen_bit_pos)
326 | USB_GAHBCFG_dma_enable;
327 /* Disable HNP and SRP, not sure it's useful because we already forced dev mode */
328 USB_GUSBCFG &= ~(USB_GUSBCFG_srpcap | USB_GUSBCFG_hnpcapp);
330 /* enable basic interrupts */
331 usb_enable_common_interrupts();
333 /* perform device model specific init */
334 core_dev_init();
337 static void usb_enable_global_interrupts(void)
339 VIC_INT_ENABLE = INTERRUPT_USB;
340 USB_GAHBCFG |= USB_GAHBCFG_glblintrmsk;
343 static void usb_disable_global_interrupts(void)
345 USB_GAHBCFG &= ~USB_GAHBCFG_glblintrmsk;
346 VIC_INT_EN_CLEAR = INTERRUPT_USB;
349 void usb_drv_init(void)
351 logf("usb_drv_init");
352 /* Enable PHY and clocks (but leave pullups disabled) */
353 as3525v2_connect();
354 /* Disable global interrupts */
355 usb_disable_global_interrupts();
356 logf("usb: synopsis id: %lx", USB_GSNPSID);
357 /* Core init */
358 core_init();
359 /* Enable global interrupts */
360 usb_enable_global_interrupts();
363 void usb_drv_exit(void)
365 logf("usb_drv_exit");
368 int usb_drv_port_speed(void)
370 return 0;
373 int usb_drv_request_endpoint(int type, int dir)
375 (void) type;
376 (void) dir;
377 return -1;
380 void usb_drv_release_endpoint(int ep)
382 (void) ep;
385 void usb_drv_cancel_all_transfers(void)
389 int usb_drv_recv(int ep, void *ptr, int len)
391 (void) ep;
392 (void) ptr;
393 (void) len;
394 return -1;
397 int usb_drv_send(int ep, void *ptr, int len)
399 (void) ep;
400 (void) ptr;
401 (void) len;
402 return -1;
405 int usb_drv_send_nonblocking(int ep, void *ptr, int len)
407 (void) ep;
408 (void) ptr;
409 (void) len;
410 return -1;
413 static void activate_ep0(void)
415 /* Setup EP0 OUT to receive setup packets and
416 * EP0 IN to transmit packets
417 * The setup takes enumeration speed into account
420 /* Setup packet size of IN ep based of enumerated speed */
421 switch((USB_DSTS & USB_DSTS_enumspd_bits) >> USB_DSTS_enumspd_bit_pos)
423 case USB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
424 case USB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
425 case USB_DSTS_ENUMSPD_FS_PHY_48MHZ:
426 /* Use 64 bytes packet size */
427 USB_DIEPCTL(0) = (USB_DIEPCTL(0) & (~USB_DEPCTL_mps_bits))
428 | (USB_DEPCTL_MPS_64 << USB_DEPCTL_mps_bit_pos);
429 break;
430 case USB_DSTS_ENUMSPD_LS_PHY_6MHZ:
431 USB_DIEPCTL(0) = (USB_DIEPCTL(0) & (~USB_DEPCTL_mps_bits))
432 | (USB_DEPCTL_MPS_8 << USB_DEPCTL_mps_bit_pos);
433 break;
434 default:
435 panicf("usb: invalid enum speed");
438 /* Enable OUT ep for receive */
439 USB_DOEPCTL(0) |= USB_DEPCTL_epena;
441 /* Clear non periodic NAK for IN ep */
442 USB_DCTL |= USB_DCTL_cgnpinnak;
445 static void ep0_out_start(void)
447 /* Setup EP0 OUT with the following parameters:
448 * packet count = 1
449 * setup packet count = 1
450 * transfer size = 8 (=sizeof setup packet)
453 USB_DOEPTSIZ(0) = (1 << USB_DEPTSIZ0_supcnt_bit_pos)
454 | (1 << USB_DEPTSIZ0_pkcnt_bit_pos)
455 | 8;
457 /* setup DMA */
458 clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */
459 USB_DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */
461 /* enable EP */
462 USB_DOEPCTL(0) |= USB_DEPCTL_epena | USB_DEPCTL_usbactep;
465 static bool handle_usb_reset(void)
467 unsigned int i;
468 logf("usb: bus reset");
470 /* Clear the Remote Wakeup Signalling */
471 USB_DCTL &= ~USB_DCTL_rmtwkupsig;
473 /* Set NAK for all OUT EPs */
474 for(i = 0; i <= USB_NUM_OUT_EP; i++)
475 USB_DOEPCTL(i) = USB_DEPCTL_snak;
477 /* Flush the NP Tx FIFO */
478 usb_flush_tx_fifos(0);
480 /* Flush the Learning Queue */
481 USB_GRSTCTL = USB_GRSTCTL_intknqflsh;
483 /* Setup interrupt masks */
484 USB_DAINTMSK = USB_DAINT_IN_EP(0) | USB_DAINT_OUT_EP(0);
485 USB_DOEPMSK = USB_DOEPINT_setup | USB_DOEPINT_xfercompl | USB_DOEPINT_ahberr
486 | USB_DOEPINT_epdisabled;
487 USB_DIEPMSK = USB_DIEPINT_xfercompl | USB_DIEPINT_timeout
488 | USB_DIEPINT_epdisabled | USB_DIEPINT_ahberr
489 | USB_DIEPINT_intknepmis;
491 /* Reset Device Address */
492 USB_DCFG &= ~USB_DCFG_devadr_bits;
494 /* setup EP0 to receive SETUP packets */
495 ep0_out_start();
496 /* Clear interrupt */
497 USB_GINTSTS = USB_GINTMSK_usbreset;
499 return true;
502 static bool handle_enum_done(void)
504 logf("usb: enum done");
506 /* Enable EP0 to receive SETUP packets */
507 activate_ep0();
509 /* Set USB turnaround time
510 * fixme: unsure about this */
511 //USB_GUSBCFG = (USB_GUSBCFG & ~USB_GUSBCFG_usbtrdtim_bits) | (5 << USB_GUSBCFG_usbtrdtim_bit_pos);
512 //panicf("usb: turnaround time is %d", (USB_GUSBCFG & USB_GUSBCFG_usbtrdtim_bits) >> USB_GUSBCFG_usbtrdtim_bit_pos);
514 /* Clear interrupt */
515 USB_GINTSTS = USB_GINTMSK_enumdone;
517 return true;
520 static bool handle_in_ep_int(void)
522 logf("usb: in ep int");
523 return false;
526 static bool handle_out_ep_int(void)
528 logf("usb: out ep int");
529 return false;
532 static void dump_intsts(char *buffer, size_t size, unsigned long sts)
534 (void) size;
535 buffer[0] = 0;
536 #define DUMP_CASE(name) \
537 if(sts & USB_GINTMSK_##name) strcat(buffer, #name " ");
539 DUMP_CASE(modemismatch)
540 DUMP_CASE(otgintr)
541 DUMP_CASE(sofintr)
542 DUMP_CASE(rxstsqlvl)
543 DUMP_CASE(nptxfempty)
544 DUMP_CASE(ginnakeff)
545 DUMP_CASE(goutnakeff)
546 DUMP_CASE(i2cintr)
547 DUMP_CASE(erlysuspend)
548 DUMP_CASE(usbsuspend)
549 DUMP_CASE(usbreset)
550 DUMP_CASE(enumdone)
551 DUMP_CASE(isooutdrop)
552 DUMP_CASE(eopframe)
553 DUMP_CASE(epmismatch)
554 DUMP_CASE(inepintr)
555 DUMP_CASE(outepintr)
556 DUMP_CASE(incomplisoin)
557 DUMP_CASE(incomplisoout)
558 DUMP_CASE(portintr)
559 DUMP_CASE(hcintr)
560 DUMP_CASE(ptxfempty)
561 DUMP_CASE(conidstschng)
562 DUMP_CASE(disconnect)
563 DUMP_CASE(sessreqintr)
564 DUMP_CASE(wkupintr)
566 buffer[strlen(buffer) - 1] = 0;
569 /* interrupt service routine */
570 void INT_USB(void)
572 static char buffer[256];
573 /* some bits in GINTSTS can be set even though we didn't enable the interrupt source
574 * so AND it with the actual mask */
575 unsigned long sts = USB_GINTSTS & USB_GINTMSK;
576 unsigned long handled_one = 0; /* mask of all listed one (either handled or not) */
578 #define HANDLED_CASE(bitmask, callfn) \
579 handled_one |= bitmask; \
580 if(sts & bitmask) \
582 if(!callfn()) \
583 goto Lerr; \
586 #define UNHANDLED_CASE(bitmask) \
587 handled_one |= bitmask; \
588 if(sts & bitmask) \
589 goto Lunhandled;
591 /* device part */
592 HANDLED_CASE(USB_GINTMSK_usbreset, handle_usb_reset)
593 HANDLED_CASE(USB_GINTMSK_enumdone, handle_enum_done)
594 HANDLED_CASE(USB_GINTMSK_inepintr, handle_in_ep_int)
595 HANDLED_CASE(USB_GINTMSK_outepintr, handle_out_ep_int)
597 /* common part */
598 UNHANDLED_CASE(USB_GINTMSK_otgintr)
599 UNHANDLED_CASE(USB_GINTMSK_conidstschng)
600 UNHANDLED_CASE(USB_GINTMSK_disconnect)
602 /* unlisted ones */
603 if(sts & ~handled_one)
604 goto Lunhandled;
606 return;
608 Lunhandled:
609 dump_intsts(buffer, sizeof buffer, sts);
610 panicf("unhandled usb int: %lx (%s)", sts, buffer);
612 Lerr:
613 dump_intsts(buffer, sizeof buffer, sts);
614 panicf("error in usb int: %lx (%s)", sts, buffer);
617 void usb_drv_set_test_mode(int mode)
619 (void) mode;
622 void usb_drv_set_address(int address)
624 (void) address;
627 void usb_drv_stall(int ep, bool stall, bool in)
629 (void) ep;
630 (void) stall;
631 (void) in;
634 bool usb_drv_stalled(int ep, bool in)
636 (void) ep;
637 (void) in;
638 return true;