first adaption of 'usbport' by Benedikt Sauter
[ppcskel.git] / usb / host / sl811hs-hcd.c
1 /*
2  * Copyright (c) 2007, Benedikt Sauter <sauter@ixbat.de>
3  * All rights reserved.
4  *
5  * Short descripton of file: sl811hs-hcdi.c
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions 
10  * are met:
11  *
12  *   * Redistributions of source code must retain the above copyright 
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above 
15  *     copyright notice, this list of conditions and the following 
16  *     disclaimer in the documentation and/or other materials provided 
17  *     with the distribution.
18  *   * Neither the name of the FH Augsburg nor the names of its 
19  *     contributors may be used to endorse or promote products derived 
20  *     from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
26  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include "host.h"
36 #include "sl811hs.h"
37 #include <wait.h>
38 #include <stdlib.h>
39
40 #include "uart.h"
41 #include "wait.h"
42
43 #include <core/core.h>
44 //#include <class/hub.h>
45 #include <usbspec/usb11spec.h>
46
47 void sl811_roothub_probe();
48 void sl811_roothub_check();
49
50 void sl811_start_transfer();
51
52 usb_device * device_on_downstream;
53
54
55 /* cuurent transferdescriptor on port a and port b */
56 usb_transfer_descriptor * td_usba;
57 usb_transfer_descriptor * td_usbb;
58
59 usb_driver sl811_roothub = {
60   .name   = "sl811_roothub",
61   .probe  = sl811_roothub_probe,
62   .check  = sl811_roothub_check,
63   .data   = NULL,
64 };
65
66 /**
67  * Find and initial root hub
68  */
69 void sl811_roothub_probe()
70 {
71   // called on n every new enumeration and at usb_register_driver  
72   // der sollte nach dem ersten aufruf igonriert werden
73   // oder diese funktion bleibt einfach leer
74   #if DEBUG
75   core.stdout("Probe: SL811 Root Hub\r\n");
76   #endif
77 }
78
79
80 /**
81  * This function is called periodical, to notice
82  * port changes after an hub
83  */
84 void sl811_roothub_check()
85 {
86   /* hier muss man nur dafuer sorgen wenn ein geaert angesteckt
87    * wird, dass der entsprechende port auf reset gesetzt wird
88    * damit das device die adresse 0 annimmt
89    * und dann muss man usb_add_device aufrufen
90    *
91    * wenn ein geraet entfernt wird muss man nur usb_remove_device aufrufen
92    * und es muss dabei das richtige geraet angegeben werden.
93    * dieses muss man sich wahrscheinlich intern im treiber
94    * merken...
95    */
96   // check for new device 
97   u16 *port_change = (u16*)sl811_roothub.data;
98   
99   u8 status = sl811_read(SL811_ISR);
100   sl811_write(SL811_ISR,SL811_ISR_DATA | SL811_ISR_SOFTIMER);
101
102   #define HUB_PORTSTATUS_C_PORT_CONNECTION 1
103   if((status & SL811_ISR_RESET)) {  // TODO und bit x von CTRL
104     // remove device if neccessary
105     if(device_on_downstream!=NULL){
106       #if USBMON
107       core.stdout("Remove Device!\r\n");
108       #endif
109       usb_remove_device(device_on_downstream);
110       device_on_downstream=NULL;
111     }
112     
113     sl811_write(SL811_ISR,SL811_ISR_RESET);
114   } else {
115     if((port_change[0] & HUB_PORTSTATUS_C_PORT_CONNECTION)){
116       #if USBMON
117       core.stdout("Find new Device!\r\n");
118       #endif
119       
120       /* init sof currently for fullspeed  (datasheet page 11)*/
121       sl811_write(SL811_CSOF,0xAE);
122       sl811_write(SL811_DATA,0xE0);
123
124       /* reset device that function can answer to address 0 */
125       sl811_write(SL811_IER,0x00);
126       sl811_write(SL811_CTRL,SL811_CTRL_ENABLESOF|SL811_CTRL_RESETENGINE);
127       sl811_write(SL811_ISR,0xff);
128       wait_ms(20);
129
130       /* start SOF generation */
131       sl811_write(SL811_CTRL,SL811_CTRL_ENABLESOF);
132       sl811_write(SL811_ISR,0xff);
133       sl811_write(SL811_E0BASE,SL811_EPCTRL_ARM);
134       wait_ms(50);
135       
136       device_on_downstream = usb_add_device();
137
138       /* set internate port state 1=device is online */
139       port_change[0]=0x00;
140
141     }
142   }
143
144   if((status & SL811_ISR_INSERT)){
145     port_change[0] |= HUB_PORTSTATUS_C_PORT_CONNECTION;
146     sl811_write(SL811_ISR,SL811_ISR_INSERT);
147   }
148
149 }
150
151
152 void hcdi_init()
153 {
154   /* find and initial host controller */
155   sl811_init();
156   u8 rev = sl811_read(SL811_REV)>>4;
157
158   switch(rev) {
159     case 1:
160       #if USBMON
161       core.stdout("Host: SL811HS v1.2 found\r\n");
162       #endif
163     break;
164     case 2:
165       #if USBMON
166       core.stdout("Host: SL811HS v1.5 found\r\n");
167       #endif
168     break;
169     default:
170       #if USBMON 
171       core.stdout("Can't find SL811!\r\n"); 
172       #endif
173       return;
174   }
175  
176   /* Disable interrupt, then wait 40 ms */
177   sl811_write(SL811_IER,0x00);
178
179   /* Initialize controller */
180   //sl811_write(SL811_CSOF,0xae);
181   sl811_write(SL811_CSOF,SL811_CSOF_MASTER);
182
183   /* clear interrupt status register with one read operation */
184   sl811_write(SL811_ISR,0xff);
185
186   /* data = hub flags */
187   u16 *port_change = (u16*)malloc(sizeof(u16));
188   port_change[0] = 0x00;
189   port_change[1] = 0x00;
190   sl811_roothub.data = (void*)port_change;
191   device_on_downstream = NULL;
192
193
194   /* register virtual root hub driver */
195   usb_register_driver(&sl811_roothub);
196
197   
198   /* activate interrupts */
199   sl811_write(SL811_IER,SL811_IER_USBA);
200 }
201
202 /**
203  * hcdi_enqueue takes usb_irp and split it into
204  * several usb packeges (SETUP,IN,OUT)
205  * In the usbstack they are transported with the
206  * usb_transfer_descriptor data structure.
207  */
208
209 u8 hcdi_enqueue(usb_transfer_descriptor *td)
210 {
211   #if LIBMODE
212   td_usba = td;
213   sl811_start_transfer();
214   #endif
215   return 1;
216 }
217
218
219 u8 hcdi_dequeue(usb_transfer_descriptor *td)
220 {
221   return 1;
222 }
223
224
225
226 void hcdi_irq()
227 {
228   core.stdout("interrupt\r\n");
229   u8 state;
230   state = sl811_read(SL811_ISR);
231   if(state & SL811_ISR_USBA) {
232     core.stdout("a done\r\n");
233   }
234   if(state & SL811_ISR_USBB) {
235     core.stdout("b done\r\n");
236   }
237   if(state & SL811_ISR_RESET) {
238     core.stdout("reset\r\n");
239   }
240   
241   if(state & SL811_ISR_INSERT) {
242     core.stdout("insert\r\n");
243   }
244
245   sl811_write(SL811_ISR,0xFF);
246 }
247
248
249
250 void sl811_start_transfer()
251 {
252   usb_transfer_descriptor * td;
253
254   #if LIBMODE
255   /* choose next free port */
256   td = td_usba;
257   /* disable a done interrupt */
258   sl811_write(SL811_IER,0x00);  
259   #endif
260
261   #if USBMON
262     //core.stdout("");
263   #endif
264
265   sl811_write(SL811_E0CONT,td->devaddress);     /* device address */
266   sl811_write(SL811_E0LEN,td->actlen);          /* number of bytes to transfer */
267   sl811_write(SL811_E0ADDR,cMemStart);          /* set address to buffer in sl811 ram */
268
269   switch(td->pid) {
270     case USB_PID_SETUP:
271       //core.stdout("*setup\r\n");
272       /* copy data into ram of sl811 */
273       sl811_write_buf(cMemStart,(unsigned char *)td->buffer,td->actlen);
274       
275       sl811_write(SL811_E0STAT,PID_SETUP|td->endpoint); /* set pid and ep */
276       sl811_write(SL811_E0CTRL,DATA0_WR);               /* send setup packet with DATA0 */
277  
278       td->state = USB_TRANSFER_DESCR_SEND;
279
280       /* wait ack */
281       #if LIBMODE
282       while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0);
283       //wait_ms(1);
284       #endif
285
286     break;
287     
288     case USB_PID_IN:
289       //core.stdout("*in\r\n");
290       #if LIBMODE
291       wait_ms(2);
292       #endif
293       
294       sl811_write(SL811_E0STAT,PID_IN|td->endpoint); /* set pid and ep */
295       sl811_write(SL811_ISR,0xff);
296      
297       /* choose data0 or data1 */
298       if(td->togl)
299         sl811_write(SL811_E0CTRL,DATA1_RD);             /* send setup packet with DATA0 */
300       else
301         sl811_write(SL811_E0CTRL,DATA0_RD);             /* send setup packet with DATA0 */
302
303       td->state = USB_TRANSFER_DESCR_SEND;
304   
305       /* wait ack */
306       #if LIBMODE
307       while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0);
308       //wait_ms(1);
309       
310       /* copy received data from internal sl811 ram */
311       sl811_read_buf(cMemStart,(unsigned char *)td->buffer,td->actlen);
312       
313       #endif
314
315     break;
316     
317     case USB_PID_OUT:
318       //core.stdout("*out\r\n");
319       #if LIBMODE
320       wait_ms(2);
321       #endif
322
323       /* copy data into ram of sl811 */
324       if(td->actlen>0)
325         sl811_write_buf(cMemStart,(unsigned char *)td->buffer,td->actlen);
326
327       sl811_write(SL811_E0STAT,PID_OUT|td->endpoint); /* set pid and ep */
328   
329       /* choose data0 or data1 */
330       if(td->togl)
331         sl811_write(SL811_E0CTRL,DATA1_WR);             /* send setup packet with DATA0 */
332       else
333         sl811_write(SL811_E0CTRL,DATA0_WR);             /* send setup packet with DATA0 */
334
335       td->state = USB_TRANSFER_DESCR_SEND;
336
337       /* wait ack */
338       #if LIBMODE
339       while((sl811_read(SL811_ISR)&SL811_ISR_USBA)==0);
340       //wait_ms(1);
341       #endif
342
343     break;
344
345
346   }
347
348
349 }
350
351