Root/
Source at commit 702b54aa47ea37158226705259ea44a1f412a9bb created 13 years 27 days ago. By Xiangfu Liu, cleanup code style, cleanup command process function | |
---|---|
1 | /* |
2 | * Copyright (C) 2009 Qi Hardware Inc., |
3 | * Author: Xiangfu Liu <xiangfu@sharism.cc> |
4 | * |
5 | * This program is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU General Public License |
7 | * version 3 as published by the Free Software Foundation. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program; if not, write to the Free Software |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA |
18 | */ |
19 | #include "usb/usb.h" |
20 | #include "usb/udc.h" |
21 | #include "target/usb_boot.h" |
22 | #include "target/xburst_types.h" |
23 | |
24 | #if defined(NANONOTE) |
25 | #include "target/jz4740.h" |
26 | #elif defined(LEPUS) |
27 | #include "target/jz4760.h" |
28 | #else |
29 | #error "Please Define [NANONOTE] or [LEPUS]" |
30 | #endif |
31 | |
32 | #define dprintf(x...) /* serial_puts(x) */ |
33 | #define TXFIFOEP0 USB_FIFO_EP0 |
34 | |
35 | extern void serial_put_hex(int ); |
36 | |
37 | u32 Bulk_in_buf[BULK_IN_BUF_SIZE]; |
38 | u32 Bulk_out_buf[BULK_OUT_BUF_SIZE]; |
39 | u32 Bulk_in_size, Bulk_in_finish, Bulk_out_size; |
40 | u16 handshake_PKT[4] = {0, 0, 0, 0}; |
41 | u8 udc_state; |
42 | |
43 | static u32 rx_buf[32]; |
44 | static u32 tx_buf[32]; |
45 | static u32 tx_size, rx_size, finished, fifo; |
46 | static u8 ep0state, USB_Version; |
47 | |
48 | static u32 fifoaddr[] = |
49 | { |
50 | TXFIFOEP0, TXFIFOEP0+4 ,TXFIFOEP0+8 |
51 | }; |
52 | |
53 | static u32 fifosize[] = { |
54 | MAX_EP0_SIZE, MAX_EP1_SIZE |
55 | }; |
56 | |
57 | void *memset(void *s, int c, size_t count) |
58 | { |
59 | char *xs = s; |
60 | |
61 | while (count--) |
62 | *xs++ = c; |
63 | return s; |
64 | } |
65 | |
66 | void *memcpy(void *dest, const void *src, size_t count) |
67 | { |
68 | char *tmp = dest; |
69 | const char *s = src; |
70 | |
71 | while (count--) |
72 | *tmp++ = *s++; |
73 | |
74 | return dest; |
75 | } |
76 | |
77 | static void udcReadFifo(u8 *ptr, int size) |
78 | { |
79 | u32 *d = (u32 *)ptr; |
80 | int s; |
81 | s = (size + 3) >> 2; |
82 | while (s--) |
83 | *d++ = REG32(fifo); |
84 | } |
85 | |
86 | static void udcWriteFifo(u8 *ptr, int size) |
87 | { |
88 | u32 *d = (u32 *)ptr; |
89 | u8 *c; |
90 | int s, q; |
91 | |
92 | if (size > 0) { |
93 | s = size >> 2; |
94 | while (s--) |
95 | REG32(fifo) = *d++; |
96 | q = size & 3; |
97 | if (q) { |
98 | c = (u8 *)d; |
99 | while (q--) |
100 | REG8(fifo) = *c++; |
101 | } |
102 | } |
103 | } |
104 | |
105 | void HW_SendPKT(int ep, const u8 *buf, int size) |
106 | { |
107 | fifo = fifoaddr[ep]; |
108 | |
109 | if (ep!=0) { |
110 | Bulk_in_size = size; |
111 | Bulk_in_finish = 0; |
112 | jz_writeb(USB_REG_INDEX, ep); |
113 | if (Bulk_in_size - Bulk_in_finish <= fifosize[ep]) { |
114 | udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), |
115 | Bulk_in_size - Bulk_in_finish); |
116 | usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); |
117 | Bulk_in_finish = Bulk_in_size; |
118 | } else { |
119 | udcWriteFifo((u8 *)((u32)buf+Bulk_in_finish), |
120 | fifosize[ep]); |
121 | usb_setb(USB_REG_INCSR, USB_INCSR_INPKTRDY); |
122 | Bulk_in_finish += fifosize[ep]; |
123 | } |
124 | } else { |
125 | tx_size = size; |
126 | finished = 0; |
127 | memcpy((void *)tx_buf, buf, size); |
128 | ep0state = USB_EP0_TX; |
129 | } |
130 | } |
131 | |
132 | void HW_GetPKT(int ep, const u8 *buf, int size) |
133 | { |
134 | memcpy((void *)buf, (u8 *)rx_buf, size); |
135 | fifo = fifoaddr[ep]; |
136 | if (rx_size > size) |
137 | rx_size -= size; |
138 | else { |
139 | size = rx_size; |
140 | rx_size = 0; |
141 | } |
142 | memcpy((u8 *)rx_buf, (u8 *)((u32)rx_buf+size), rx_size); |
143 | } |
144 | |
145 | static USB_DeviceDescriptor devDesc = |
146 | { |
147 | sizeof(USB_DeviceDescriptor), |
148 | DEVICE_DESCRIPTOR, //1 |
149 | 0x0200, //Version 2.0 |
150 | 0xff, //Vendor spec class |
151 | 0xff, |
152 | 0xff, |
153 | 64, /* Ep0 FIFO size */ |
154 | 0x601a, //vendor ID |
155 | 0x4740, //Product ID |
156 | 0xffff, |
157 | 0x00, |
158 | 0x00, |
159 | 0x00, |
160 | 0x01 |
161 | }; |
162 | |
163 | #define CONFIG_DESCRIPTOR_LEN (sizeof(USB_ConfigDescriptor) + \ |
164 | sizeof(USB_InterfaceDescriptor) + \ |
165 | sizeof(USB_EndPointDescriptor) * 2) |
166 | |
167 | static struct { |
168 | USB_ConfigDescriptor configuration_descriptor; |
169 | USB_InterfaceDescriptor interface_descritor; |
170 | USB_EndPointDescriptor endpoint_descriptor[2]; |
171 | } __attribute__ ((packed)) confDesc = { |
172 | { |
173 | sizeof(USB_ConfigDescriptor), |
174 | CONFIGURATION_DESCRIPTOR, |
175 | CONFIG_DESCRIPTOR_LEN, |
176 | 0x01, |
177 | 0x01, |
178 | 0x00, |
179 | 0xc0, // Self Powered, no remote wakeup |
180 | 0x64 // Maximum power consumption 2000 mA |
181 | }, |
182 | { |
183 | sizeof(USB_InterfaceDescriptor), |
184 | INTERFACE_DESCRIPTOR, |
185 | 0x00, |
186 | 0x00, |
187 | 0x02, /* ep number */ |
188 | 0xff, |
189 | 0xff, |
190 | 0xff, |
191 | 0x00 |
192 | }, |
193 | { |
194 | { |
195 | sizeof(USB_EndPointDescriptor), |
196 | ENDPOINT_DESCRIPTOR, |
197 | (1 << 7) | 1,// endpoint 2 is IN endpoint |
198 | 2, /* bulk */ |
199 | 512, |
200 | 16 |
201 | }, |
202 | { |
203 | sizeof(USB_EndPointDescriptor), |
204 | ENDPOINT_DESCRIPTOR, |
205 | (0 << 7) | 1,// endpoint 5 is OUT endpoint |
206 | 2, /* bulk */ |
207 | 512, /* OUT EP FIFO size */ |
208 | 16 |
209 | } |
210 | } |
211 | }; |
212 | |
213 | void sendDevDescString(int size) |
214 | { |
215 | u16 str_ret[13] = { |
216 | 0x031a,//0x1a=26 byte |
217 | 0x0041, |
218 | 0x0030, |
219 | 0x0030, |
220 | 0x0041, |
221 | 0x0030, |
222 | 0x0030, |
223 | 0x0041, |
224 | 0x0030, |
225 | 0x0030, |
226 | 0x0041, |
227 | 0x0030, |
228 | 0x0030 |
229 | }; |
230 | if(size >= 26) |
231 | size = 26; |
232 | str_ret[0] = (0x0300 | size); |
233 | HW_SendPKT(0, (u8 *)str_ret,size); |
234 | |
235 | } |
236 | |
237 | void sendDevDesc(int size) |
238 | { |
239 | switch (size) { |
240 | case 18: |
241 | HW_SendPKT(0, (u8 *)&devDesc, sizeof(devDesc)); |
242 | break; |
243 | default: |
244 | HW_SendPKT(0, (u8 *)&devDesc, 8); |
245 | break; |
246 | } |
247 | } |
248 | |
249 | void sendConfDesc(int size) |
250 | { |
251 | switch (size) { |
252 | case 9: |
253 | HW_SendPKT(0, (u8 *)&confDesc, 9); |
254 | break; |
255 | case 8: |
256 | HW_SendPKT(0, (u8 *)&confDesc, 8); |
257 | break; |
258 | default: |
259 | HW_SendPKT(0, (u8 *)&confDesc, sizeof(confDesc)); |
260 | break; |
261 | } |
262 | } |
263 | |
264 | void EP0_init(u32 out, u32 out_size, u32 in, u32 in_size) |
265 | { |
266 | confDesc.endpoint_descriptor[0].bEndpointAddress = (1<<7) | in; |
267 | confDesc.endpoint_descriptor[0].wMaxPacketSize = in_size; |
268 | confDesc.endpoint_descriptor[1].bEndpointAddress = (0<<7) | out; |
269 | confDesc.endpoint_descriptor[1].wMaxPacketSize = out_size; |
270 | } |
271 | |
272 | static void udc_reset(void) |
273 | { |
274 | u8 byte; |
275 | ep0state = USB_EP0_IDLE; |
276 | Bulk_in_size = 0; |
277 | Bulk_in_finish = 0; |
278 | Bulk_out_size = 0; |
279 | udc_state = IDLE; |
280 | tx_size = 0; |
281 | rx_size = 0; |
282 | finished = 0; |
283 | /* Enable the USB PHY */ |
284 | // REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; |
285 | /* Disable interrupts */ |
286 | byte=jz_readb(USB_REG_POWER); |
287 | jz_writew(USB_REG_INTRINE, 0); |
288 | jz_writew(USB_REG_INTROUTE, 0); |
289 | jz_writeb(USB_REG_INTRUSBE, 0); |
290 | jz_writeb(USB_REG_FADDR, 0); |
291 | jz_writeb(USB_REG_POWER, 0x60); //High speed |
292 | jz_writeb(USB_REG_INDEX, 0); |
293 | jz_writeb(USB_REG_CSR0, 0xc0); |
294 | jz_writeb(USB_REG_INDEX, 1); |
295 | jz_writew(USB_REG_INMAXP, 512); |
296 | jz_writew(USB_REG_INCSR, 0x2048); |
297 | jz_writeb(USB_REG_INDEX, 1); |
298 | jz_writew(USB_REG_OUTMAXP, 512); |
299 | jz_writew(USB_REG_OUTCSR, 0x0090); |
300 | jz_writew(USB_REG_INTRINE, 0x3); //enable intr |
301 | jz_writew(USB_REG_INTROUTE, 0x2); |
302 | jz_writeb(USB_REG_INTRUSBE, 0x4); |
303 | |
304 | byte = jz_readb(USB_REG_POWER); |
305 | if ((byte&0x10) == 0) { |
306 | jz_writeb(USB_REG_INDEX, 1); |
307 | jz_writew(USB_REG_INMAXP, 64); |
308 | jz_writew(USB_REG_INCSR, 0x2048); |
309 | jz_writeb(USB_REG_INDEX, 1); |
310 | jz_writew(USB_REG_OUTMAXP, 64); |
311 | jz_writew(USB_REG_OUTCSR, 0x0090); |
312 | USB_Version = USB_FS; |
313 | fifosize[1] = 64; |
314 | EP0_init(1, 64, 1, 64); |
315 | } else { |
316 | jz_writeb(USB_REG_INDEX, 1); |
317 | jz_writew(USB_REG_INMAXP, 512); |
318 | jz_writew(USB_REG_INCSR, 0x2048); |
319 | jz_writeb(USB_REG_INDEX, 1); |
320 | jz_writew(USB_REG_OUTMAXP, 512); |
321 | jz_writew(USB_REG_OUTCSR, 0x0090); |
322 | USB_Version = USB_HS; |
323 | fifosize[1] = 512; |
324 | EP0_init(1, 512, 1, 512); |
325 | } |
326 | |
327 | } |
328 | |
329 | |
330 | void usbHandleStandDevReq(u8 *buf) |
331 | { |
332 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
333 | switch (dreq->bRequest) { |
334 | case GET_DESCRIPTOR: |
335 | if (dreq->bmRequestType == 0x80) /* Dev2Host */ |
336 | switch(dreq->wValue >> 8) { |
337 | case DEVICE_DESCRIPTOR: |
338 | dprintf("get device\n"); |
339 | sendDevDesc(dreq->wLength); |
340 | break; |
341 | case CONFIGURATION_DESCRIPTOR: |
342 | dprintf("get config\n"); |
343 | sendConfDesc(dreq->wLength); |
344 | break; |
345 | case STRING_DESCRIPTOR: |
346 | if (dreq->wLength == 0x02) |
347 | HW_SendPKT(0, "\x04\x03", 2); |
348 | else |
349 | sendDevDescString(dreq->wLength); |
350 | break; |
351 | } |
352 | dprintf("\nSet ep0state=TX!"); |
353 | ep0state = USB_EP0_TX; |
354 | |
355 | break; |
356 | case SET_ADDRESS: |
357 | dprintf("\nSET_ADDRESS!"); |
358 | jz_writeb(USB_REG_FADDR,dreq->wValue); |
359 | break; |
360 | case GET_STATUS: |
361 | switch (dreq->bmRequestType) { |
362 | case 80: /* device */ |
363 | HW_SendPKT(0, "\x01\x00", 2); |
364 | break; |
365 | case 81: /* interface */ |
366 | case 82: /* ep */ |
367 | HW_SendPKT(0, "\x00\x00", 2); |
368 | break; |
369 | } |
370 | ep0state=USB_EP0_TX; |
371 | break; |
372 | case CLEAR_FEATURE: |
373 | case SET_CONFIGURATION: |
374 | case SET_INTERFACE: |
375 | case SET_FEATURE: |
376 | break; |
377 | } |
378 | } |
379 | |
380 | void usbHandleVendorReq(u8 *buf) |
381 | { |
382 | int ret_state; |
383 | USB_DeviceRequest *dreq = (USB_DeviceRequest *)buf; |
384 | switch (dreq->bRequest) { |
385 | case VR_GET_CUP_INFO: |
386 | ret_state = GET_CUP_INFO_Handle(); |
387 | break; |
388 | case VR_SET_DATA_ADDERSS: |
389 | ret_state = SET_DATA_ADDERSS_Handle(buf); |
390 | break; |
391 | case VR_SET_DATA_LENGTH: |
392 | ret_state = SET_DATA_LENGTH_Handle(buf); |
393 | break; |
394 | case VR_FLUSH_CACHES: |
395 | ret_state = FLUSH_CACHES_Handle(); |
396 | break; |
397 | case VR_PROGRAM_START1: |
398 | ret_state = PROGRAM_START1_Handle(buf); |
399 | break; |
400 | case VR_PROGRAM_START2: |
401 | ret_state = PROGRAM_START2_Handle(buf); |
402 | break; |
403 | case VR_NOR_OPS: |
404 | ret_state = NOR_OPS_Handle(buf); |
405 | Bulk_out_size = 0; |
406 | break; |
407 | case VR_NAND_OPS: |
408 | NAND_OPS_Handle(buf); |
409 | Bulk_out_size = 0; |
410 | break; |
411 | case VR_CONFIGRATION: |
412 | ret_state = CONFIGRATION_Handle(buf); |
413 | handshake_PKT[3] = (u16)ret_state; |
414 | HW_SendPKT(1, (u8 *)handshake_PKT, sizeof(handshake_PKT)); |
415 | Bulk_out_size = 0; |
416 | break; |
417 | case VR_SDRAM_OPS: |
418 | SDRAM_OPS_Handle(buf); |
419 | Bulk_out_size = 0; |
420 | break; |
421 | } |
422 | } |
423 | |
424 | void Handshake_PKT() |
425 | { |
426 | if (udc_state!=IDLE) |
427 | { |
428 | HW_SendPKT(1, (u8 *)handshake_PKT, sizeof(handshake_PKT)); |
429 | udc_state = IDLE; |
430 | dprintf("\n Send handshake PKT!"); |
431 | } |
432 | } |
433 | |
434 | void usbHandleDevReq(u8 *buf) |
435 | { |
436 | switch ((buf[0] & (3 << 5)) >> 5) { |
437 | case 0: /* Standard request */ |
438 | usbHandleStandDevReq(buf); |
439 | break; |
440 | case 1: /* Class request */ |
441 | break; |
442 | case 2: /* Vendor request */ |
443 | usbHandleVendorReq(buf); |
444 | break; |
445 | } |
446 | } |
447 | |
448 | void EP0_Handler () |
449 | { |
450 | u8 byCSR0; |
451 | |
452 | /* Read CSR0 */ |
453 | jz_writeb(USB_REG_INDEX, 0); |
454 | byCSR0 = jz_readb(USB_REG_CSR0); |
455 | |
456 | /* Check for SentStall |
457 | * if sendtall is set ,clear the sendstall bit */ |
458 | if (byCSR0 & USB_CSR0_SENTSTALL) { |
459 | jz_writeb(USB_REG_CSR0, (byCSR0 & ~USB_CSR0_SENDSTALL)); |
460 | ep0state = USB_EP0_IDLE; |
461 | dprintf("\nSentstall!"); |
462 | return; |
463 | } |
464 | |
465 | /* Check for SetupEnd */ |
466 | if (byCSR0 & USB_CSR0_SETUPEND) { |
467 | jz_writeb(USB_REG_CSR0, (byCSR0 | USB_CSR0_SVDSETUPEND)); |
468 | ep0state = USB_EP0_IDLE; |
469 | dprintf("\nSetupend!"); |
470 | return; |
471 | } |
472 | /* Call relevant routines for endpoint 0 state */ |
473 | if (ep0state == USB_EP0_IDLE) { |
474 | if (byCSR0 & USB_CSR0_OUTPKTRDY) { //There are datas in fifo |
475 | USB_DeviceRequest *dreq; |
476 | fifo = fifoaddr[0]; |
477 | udcReadFifo((u8 *)rx_buf, sizeof(USB_DeviceRequest)); |
478 | usb_setb(USB_REG_CSR0, 0x48);//clear OUTRD bit |
479 | dreq = (USB_DeviceRequest *)rx_buf; |
480 | usbHandleDevReq((u8 *)rx_buf); |
481 | } else |
482 | dprintf("0:R DATA\n"); |
483 | |
484 | rx_size = 0; |
485 | } |
486 | |
487 | if (ep0state == USB_EP0_TX) { |
488 | fifo=fifoaddr[0]; |
489 | if (tx_size - finished <= 64) { |
490 | udcWriteFifo((u8 *)((u32)tx_buf+finished), |
491 | tx_size - finished); |
492 | finished = tx_size; |
493 | usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); |
494 | usb_setb(USB_REG_CSR0, USB_CSR0_DATAEND); //Set dataend! |
495 | ep0state = USB_EP0_IDLE; |
496 | } else { |
497 | udcWriteFifo((u8 *)((u32)tx_buf+finished), 64); |
498 | usb_setb(USB_REG_CSR0, USB_CSR0_INPKTRDY); |
499 | finished += 64; |
500 | } |
501 | } |
502 | return; |
503 | } |
504 | |
505 | void EPIN_Handler(u8 EP) |
506 | { |
507 | jz_writeb(USB_REG_INDEX, EP); |
508 | fifo = fifoaddr[EP]; |
509 | |
510 | if (Bulk_in_size-Bulk_in_finish==0) { |
511 | Handshake_PKT(); |
512 | return; |
513 | } |
514 | |
515 | if (Bulk_in_size - Bulk_in_finish <= fifosize[EP]) { |
516 | udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), |
517 | Bulk_in_size - Bulk_in_finish); |
518 | usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); |
519 | Bulk_in_finish = Bulk_in_size; |
520 | } else { |
521 | udcWriteFifo((u8 *)((u32)Bulk_in_buf+Bulk_in_finish), |
522 | fifosize[EP]); |
523 | usb_setw(USB_REG_INCSR, USB_INCSR_INPKTRDY); |
524 | Bulk_in_finish += fifosize[EP]; |
525 | } |
526 | } |
527 | |
528 | void EPOUT_Handler(u8 EP) |
529 | { |
530 | u32 size; |
531 | jz_writeb(USB_REG_INDEX, EP); |
532 | size = jz_readw(USB_REG_OUTCOUNT); |
533 | fifo = fifoaddr[EP]; |
534 | udcReadFifo((u8 *)((u32)Bulk_out_buf+Bulk_out_size), size); |
535 | usb_clearb(USB_REG_OUTCSR,USB_OUTCSR_OUTPKTRDY); |
536 | Bulk_out_size += size; |
537 | dprintf("\nEPOUT_handle return!"); |
538 | } |
539 | |
540 | void udc4740Proc () |
541 | { |
542 | volatile u8 IntrUSB; |
543 | volatile u16 IntrIn; |
544 | volatile u16 IntrOut; |
545 | /* Read interrupt registers */ |
546 | IntrUSB = jz_readb(USB_REG_INTRUSB); |
547 | IntrIn = jz_readw(USB_REG_INTRIN); |
548 | IntrOut = jz_readw(USB_REG_INTROUT); |
549 | |
550 | if (IntrUSB == 0 && IntrIn == 0 && IntrOut == 0) |
551 | return; |
552 | |
553 | if (IntrIn & 2) { |
554 | dprintf("\nUDC EP1 IN operation!"); |
555 | EPIN_Handler(1); |
556 | } |
557 | |
558 | if (IntrOut & 2) { |
559 | dprintf("\nUDC EP1 OUT operation!"); |
560 | EPOUT_Handler(1); |
561 | } |
562 | |
563 | if (IntrUSB & USB_INTR_RESET) { |
564 | dprintf("\nUDC reset intrupt!"); |
565 | udc_reset(); |
566 | } |
567 | |
568 | /* Check for endpoint 0 interrupt */ |
569 | if (IntrIn & USB_INTR_EP0) { |
570 | dprintf("\nUDC EP0 operations!"); |
571 | EP0_Handler(); |
572 | } |
573 | |
574 | if (USB_Version == USB_FS) |
575 | IntrIn = jz_readw(USB_REG_INTRIN); |
576 | return; |
577 | } |
578 | |
579 | void usb_main() |
580 | { |
581 | u8 byte; |
582 | |
583 | __dcache_writeback_all(); |
584 | __icache_invalidate_all(); |
585 | |
586 | ep0state = USB_EP0_IDLE; |
587 | Bulk_in_size = 0; |
588 | Bulk_in_finish = 0; |
589 | Bulk_out_size = 0; |
590 | udc_state = IDLE; |
591 | tx_size = 0; |
592 | rx_size = 0; |
593 | finished = 0; |
594 | |
595 | byte = jz_readb(USB_REG_POWER); |
596 | if ((byte&0x10) == 0) { |
597 | USB_Version = USB_FS; |
598 | fifosize[1] = 64; |
599 | EP0_init(1, 64, 1, 64); |
600 | } else { |
601 | USB_Version = USB_HS; |
602 | fifosize[1] = 512; |
603 | EP0_init(1, 512, 1, 512); |
604 | } |
605 | |
606 | serial_puts("\n Init UDC"); |
607 | USB_Version = USB_HS; |
608 | |
609 | while (1) |
610 | udc4740Proc(); |
611 | } |
612 |