/* EHCI glue. A bit hacky for the moment. needs cleaning.. Copyright (C) 2008 kwiirk. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "syscalls.h" #include "ehci_types.h" #include "utils.h" #include "ehci_interrupt.h" #include "swi_mload.h" #define static #define inline extern #define readl(a) (*((volatile u32*)(a))) #define writel(v,a) do{*((volatile u32*)(a))=(v);}while(0) #define ehci_dbg(a...) debug_printf(a) #define printk(a...) debug_printf(a) #define get_timer() (*(((volatile u32*)0x0D800010))) void BUG(void) { debug_printf("bug\n"); // stack_trace(); // while(1); } #define BUG_ON(a) if(a)BUG() void ehci_usleep(int usec); void ehci_msleep(int msec); /* void udelay(int usec) { u32 tmr,temp; u32 time_usec; tmr = get_timer(); time_usec=2*usec; while (1) {temp=get_timer()-tmr;if(temp > time_usec) break;} } void msleep(int msec)//@todo not really sleeping.. { u32 tmr,temp; u32 time_usec; tmr = get_timer(); time_usec=2048*msec; while (1) {temp=get_timer()-tmr;if(temp > time_usec) break;} } */ extern u32 __exe_start_virt__; extern u32 __ram_start_virt__; extern u32 ios_thread_stack; #define cpu_to_le32(a) swab32(a) #define le32_to_cpu(a) swab32(a) #define cpu_to_le16(a) swab16(a) #define le16_to_cpu(a) swab16(a) #define cpu_to_be32(a) (a) #define be32_to_cpu(a) (a) void print_hex_dump_bytes(char *header,int prefix,u8 *buf,int len) { int i; if (len>0x100)len=0x100; debug_printf("%s %08X\n",header,(u32)buf); for (i=0;iqtd_dma; } void init_qh_and_qtd(void) { int n; struct ehci_qtd * qtd; struct ehci_qh * qh; if(!qh_header) { //u32 mem = (u32) USB_Alloc(4096*3); //mem=(mem+4095) & ~4095; qh_header= (struct ehci_qh *) ehci->async;//mem; qtd_header= (struct ehci_qtd *) ehci->qtds[0]; } qtd=qtd_header;//= (struct ehci_qtd *) (((u32)qh_header)+4096); for(n=0;nqtds[n]=qtd; memset((void *) ehci->qtds[n], 0, sizeof(struct ehci_qtd)); ehci_dma_map_bidir((void *) ehci->qtds[n],sizeof(struct ehci_qtd)); qtd=(struct ehci_qtd *) (((((u32) qtd)+sizeof(struct ehci_qtd)+31) & ~31)); } for(n=0;nqh_dma = ehci_virt_to_dma(qh); qh_pointer[n]->hw_info1 = cpu_to_hc32((QH_HEAD*(n!=0))); qh_pointer[n]->hw_info2 = cpu_to_hc32(0); qh_pointer[n]->hw_token = cpu_to_hc32( QTD_STS_HALT); qh=(struct ehci_qh *) (((((u32) qh)+sizeof(struct ehci_qh)+31) & ~31)); qh_pointer[n]->hw_next = QH_NEXT( ehci_virt_to_dma(qh)); qh_pointer[n]->hw_qtd_next =EHCI_LIST_END(); qh_pointer[n]->hw_alt_next = EHCI_LIST_END(); ehci_dma_map_bidir((void *) qh_pointer[n],sizeof(struct ehci_qh)); } n--; qh_pointer[n]->hw_next = QH_NEXT( ehci_virt_to_dma(qh_header)); ehci_dma_map_bidir((void *) qh_pointer[n],sizeof(struct ehci_qh)); } void create_qtd_dummy(void) { int n; struct ehci_qtd * qtd, *qtd_next; qtd=qtd_dummy_first; for(n=0;;n++) { qtd_next=(struct ehci_qtd *) (((((u32) qtd)+sizeof(struct ehci_qtd)+31) & ~31)); ehci_qtd_init(qtd); //qtd_fill( qtd, 0, 0, QTD_STS_HALT, 0); if(n<3) { qtd->hw_next= QTD_NEXT(qtd_next->qtd_dma); qtd->hw_alt_next= EHCI_LIST_END(); //QTD_NEXT(qtd_next->qtd_dma); ehci_dma_map_bidir((void *) qtd,sizeof(struct ehci_qtd)); } else { ehci_dma_map_bidir(qtd,sizeof(struct ehci_qtd)); break; } qtd=qtd_next; } } /* int hola(void *i, void *o) { int n; for(n=0;n<10;n++) { *((volatile u32 *)0x0d8000c0) ^=0x20; ehci_mdelay(50); } } */ void reinit_ehci_headers(void) { init_qh_and_qtd(); create_qtd_dummy(); ehci->async= qh_pointer[0]; ehci->asyncqh= qh_pointer[1]; in_qh=qh_pointer[2]; out_qh=qh_pointer[3]; dummy_qh=qh_pointer[4]; ehci_dma_unmap_bidir((dma_addr_t) ehci->async,sizeof(struct ehci_qh)); ehci->async->ehci = ehci; ehci->async->qtd_head = NULL; ehci->async->qh_dma = ehci_virt_to_dma(ehci->async); ehci->async->hw_next = QH_NEXT(dummy_qh->qh_dma/* ehci->async->qh_dma*/); ehci->async->hw_info1 = cpu_to_hc32( QH_HEAD); ehci->async->hw_info2 = cpu_to_hc32( 0); ehci->async->hw_token = cpu_to_hc32( QTD_STS_HALT); ehci->async->hw_qtd_next =EHCI_LIST_END(); ehci->async->hw_alt_next =EHCI_LIST_END(); //QTD_NEXT(get_qtd_dummy()); ehci_dma_map_bidir(ehci->async,sizeof(struct ehci_qh)); ehci_dma_unmap_bidir((dma_addr_t)ehci->asyncqh,sizeof(struct ehci_qh)); ehci->asyncqh->ehci = ehci; ehci->asyncqh->qtd_head = NULL; ehci->asyncqh->qh_dma = ehci_virt_to_dma(ehci->asyncqh); ehci_dma_unmap_bidir((dma_addr_t)in_qh,sizeof(struct ehci_qh)); in_qh->ehci = ehci; in_qh->qtd_head = NULL; in_qh->qh_dma = ehci_virt_to_dma(in_qh); ehci_dma_map_bidir(in_qh,sizeof(struct ehci_qh)); ehci_dma_unmap_bidir((dma_addr_t)out_qh,sizeof(struct ehci_qh)); out_qh->ehci = ehci; out_qh->qtd_head = NULL; out_qh->qh_dma = ehci_virt_to_dma(out_qh); ehci_dma_map_bidir(out_qh,sizeof(struct ehci_qh)); } int tiny_ehci_init(void) { int i; ehci = &_ehci; if(usb_os_init()<0) return -1; if(1) { // From Hermes: ohci mem is readed from dev/mload: (ehci init is from here) /* int fd; fd = os_open("/dev/mload",1); if(fd<0) return -1; ehci= (struct ehci_hcd *) os_ioctlv(fd, MLOAD_GET_EHCI_DATA ,0,0,0); os_close(fd); */ ehci=swi_mload_EHCI_data(); // stops EHCI ehci_writel( 0x00010020 , &ehci->regs->command); do { if(!(ehci_readl( &ehci->regs->command) & 1))break; } while(1); ehci_dma_map_bidir(ehci,sizeof(struct ehci_hcd)); for (i = 0; i < DEFAULT_I_TDPS; i++) { ehci->periodic [i] = EHCI_LIST_END(); ehci_dma_map_bidir((void *) ehci->periodic [i],4); } reinit_ehci_headers(); ////////////////////////////////////////////////////////////////////////////////////////////// /* WARNING: This ignore the port 1 (external) and 2,3 (internals) for USB 2.0 operations */ /* from cIOS mload 1.6 port 1 is forced to USB 1.1. Only port 0 can work as USB 2.0 */ ehci->num_port=2; ehci_release_ports(); //ehci_writel( 0x00080021, &ehci->regs->command); //ehci_writel(0, &ehci->regs->frame_list); ehci_writel(ehci->async->qh_dma, &ehci->regs->async_next); ehci_writel (/*INTR_MASK*/STS_PCD, &ehci->regs->intr_enable); #define t125us (1) ehci_writel( (t125us<<16) | 0x0021 , &ehci->regs->command); ehci_readl( &ehci->regs->command); //swi_mload_led_on(); //swi_mload_call_func(hola,NULL,NULL); ///////////////////////////////////////////////////////////////////////////////////////////// } return 0; }