/* * Copyright (c) 2007, Benedikt Sauter * All rights reserved. * * Short descripton of file: sl811hs-hcdi.c * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the FH Augsburg nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "host.h" #include "sl811hs.h" #include #include #include "uart.h" #include "wait.h" #include //#include #include void sl811_roothub_probe(); void sl811_roothub_check(); void sl811_start_transfer(); usb_device * device_on_downstream; /* cuurent transferdescriptor on port a and port b */ usb_transfer_descriptor * td_usba; usb_transfer_descriptor * td_usbb; usb_driver sl811_roothub = { .name = "sl811_roothub", .probe = sl811_roothub_probe, .check = sl811_roothub_check, .data = NULL, }; /** * Find and initial root hub */ void sl811_roothub_probe() { // called on n every new enumeration and at usb_register_driver // der sollte nach dem ersten aufruf igonriert werden // oder diese funktion bleibt einfach leer #if DEBUG core.stdout("Probe: SL811 Root Hub\r\n"); #endif } /** * This function is called periodical, to notice * port changes after an hub */ void sl811_roothub_check() { /* hier muss man nur dafuer sorgen wenn ein geaert angesteckt * wird, dass der entsprechende port auf reset gesetzt wird * damit das device die adresse 0 annimmt * und dann muss man usb_add_device aufrufen * * wenn ein geraet entfernt wird muss man nur usb_remove_device aufrufen * und es muss dabei das richtige geraet angegeben werden. * dieses muss man sich wahrscheinlich intern im treiber * merken... */ // check for new device u16 *port_change = (u16*)sl811_roothub.data; u8 status = sl811_read(SL811_ISR); sl811_write(SL811_ISR,SL811_ISR_DATA | SL811_ISR_SOFTIMER); #define HUB_PORTSTATUS_C_PORT_CONNECTION 1 if((status & SL811_ISR_RESET)) { // TODO und bit x von CTRL // remove device if neccessary if(device_on_downstream!=NULL){ #if USBMON core.stdout("Remove Device!\r\n"); #endif usb_remove_device(device_on_downstream); device_on_downstream=NULL; } sl811_write(SL811_ISR,SL811_ISR_RESET); } else { if((port_change[0] & HUB_PORTSTATUS_C_PORT_CONNECTION)){ #if USBMON core.stdout("Find new Device!\r\n"); #endif /* init sof currently for fullspeed (datasheet page 11)*/ sl811_write(SL811_CSOF,0xAE); sl811_write(SL811_DATA,0xE0); /* reset device that function can answer to address 0 */ sl811_write(SL811_IER,0x00); sl811_write(SL811_CTRL,SL811_CTRL_ENABLESOF|SL811_CTRL_RESETENGINE); sl811_write(SL811_ISR,0xff); wait_ms(20); /* start SOF generation */ sl811_write(SL811_CTRL,SL811_CTRL_ENABLESOF); sl811_write(SL811_ISR,0xff); sl811_write(SL811_E0BASE,SL811_EPCTRL_ARM); wait_ms(50); device_on_downstream = usb_add_device(); /* set internate port state 1=device is online */ port_change[0]=0x00; } } if((status & SL811_ISR_INSERT)){ port_change[0] |= HUB_PORTSTATUS_C_PORT_CONNECTION; sl811_write(SL811_ISR,SL811_ISR_INSERT); } } void hcdi_init() { /* find and initial host controller */ sl811_init(); u8 rev = sl811_read(SL811_REV)>>4; switch(rev) { case 1: #if USBMON core.stdout("Host: SL811HS v1.2 found\r\n"); #endif break; case 2: #if USBMON core.stdout("Host: SL811HS v1.5 found\r\n"); #endif break; default: #if USBMON core.stdout("Can't find SL811!\r\n"); #endif return; } /* Disable interrupt, then wait 40 ms */ sl811_write(SL811_IER,0x00); /* Initialize controller */ //sl811_write(SL811_CSOF,0xae); sl811_write(SL811_CSOF,SL811_CSOF_MASTER); /* clear interrupt status register with one read operation */ sl811_write(SL811_ISR,0xff); /* data = hub flags */ u16 *port_change = (u16*)malloc(sizeof(u16)); port_change[0] = 0x00; port_change[1] = 0x00; sl811_roothub.data = (void*)port_change; device_on_downstream = NULL; /* register virtual root hub driver */ usb_register_driver(&sl811_roothub); /* activate interrupts */ sl811_write(SL811_IER,SL811_IER_USBA); } /** * hcdi_enqueue takes usb_irp and split it into * several usb packeges (SETUP,IN,OUT) * In the usbstack they are transported with the * usb_transfer_descriptor data structure. */ u8 hcdi_enqueue(usb_transfer_descriptor *td) { #if LIBMODE td_usba = td; sl811_start_transfer(); #endif return 1; } u8 hcdi_dequeue(usb_transfer_descriptor *td) { return 1; } void hcdi_irq() { core.stdout("interrupt\r\n"); u8 state; state = sl811_read(SL811_ISR); if(state & SL811_ISR_USBA) { core.stdout("a done\r\n"); } if(state & SL811_ISR_USBB) { core.stdout("b done\r\n"); } if(state & SL811_ISR_RESET) { core.stdout("reset\r\n"); } if(state & SL811_ISR_INSERT) { core.stdout("insert\r\n"); } sl811_write(SL811_ISR,0xFF); } void sl811_start_transfer() { usb_transfer_descriptor * td; #if LIBMODE /* choose next free port */ td = td_usba; /* disable a done interrupt */ sl811_write(SL811_IER,0x00); #endif #if USBMON //core.stdout(""); #endif sl811_write(SL811_E0CONT,td->devaddress); /* device address */ sl811_write(SL811_E0LEN,td->actlen); /* number of bytes to transfer */ sl811_write(SL811_E0ADDR,cMemStart); /* set address to buffer in sl811 ram */ switch(td->pid) { case USB_PID_SETUP: //core.stdout("*setup\r\n"); /* copy data into ram of sl811 */ sl811_write_buf(cMemStart,(unsigned char *)td->buffer,td->actlen); sl811_write(SL811_E0STAT,PID_SETUP|td->endpoint); /* set pid and ep */ sl811_write(SL811_E0CTRL,DATA0_WR); /* send setup packet with DATA0 */ td->state = USB_TRANSFER_DESCR_SEND; /* wait ack */ #if LIBMODE while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0); //wait_ms(1); #endif break; case USB_PID_IN: //core.stdout("*in\r\n"); #if LIBMODE wait_ms(2); #endif sl811_write(SL811_E0STAT,PID_IN|td->endpoint); /* set pid and ep */ sl811_write(SL811_ISR,0xff); /* choose data0 or data1 */ if(td->togl) sl811_write(SL811_E0CTRL,DATA1_RD); /* send setup packet with DATA0 */ else sl811_write(SL811_E0CTRL,DATA0_RD); /* send setup packet with DATA0 */ td->state = USB_TRANSFER_DESCR_SEND; /* wait ack */ #if LIBMODE while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0); //wait_ms(1); /* copy received data from internal sl811 ram */ sl811_read_buf(cMemStart,(unsigned char *)td->buffer,td->actlen); #endif break; case USB_PID_OUT: //core.stdout("*out\r\n"); #if LIBMODE wait_ms(2); #endif /* copy data into ram of sl811 */ if(td->actlen>0) sl811_write_buf(cMemStart,(unsigned char *)td->buffer,td->actlen); sl811_write(SL811_E0STAT,PID_OUT|td->endpoint); /* set pid and ep */ /* choose data0 or data1 */ if(td->togl) sl811_write(SL811_E0CTRL,DATA1_WR); /* send setup packet with DATA0 */ else sl811_write(SL811_E0CTRL,DATA0_WR); /* send setup packet with DATA0 */ td->state = USB_TRANSFER_DESCR_SEND; /* wait ack */ #if LIBMODE while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0); //wait_ms(1); #endif break; } }