Modules/FS_InitRD - Added libaxwin3
[tpg/acess2.git] / Modules / USB / Core / uhci.c
1 /*
2  * Acess 2 USB Stack
3  * Universal Host Controller Interface
4  */
5 #define DEBUG   1
6 #include <acess.h>
7 #include <vfs.h>
8 #include <drv_pci.h>
9 #include <modules.h>
10 #include "usb.h"
11 #include "uhci.h"
12
13 // === CONSTANTS ===
14 #define MAX_CONTROLLERS 4
15 #define NUM_TDs 1024
16
17 // === PROTOTYPES ===
18  int    UHCI_Initialise();
19 void    UHCI_Cleanup();
20 tUHCI_TD        *UHCI_int_AllocateTD(tUHCI_Controller *Cont);
21 void    UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD);
22 void    *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, int bIOC, void *Data, size_t Length);
23 void    *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length);
24 void    *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length);
25 void    *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length);
26  int    UHCI_Int_InitHost(tUHCI_Controller *Host);
27 void    UHCI_InterruptHandler(int IRQ, void *Ptr);
28
29 // === GLOBALS ===
30 tUHCI_TD        gaUHCI_TDPool[NUM_TDs];
31 tUHCI_Controller        gUHCI_Controllers[MAX_CONTROLLERS];
32 tUSBHost        gUHCI_HostDef = {
33         .SendIN = UHCI_DataIN,
34         .SendOUT = UHCI_DataOUT,
35         .SendSETUP = UHCI_SendSetup,
36         };
37
38 // === CODE ===
39 /**
40  * \fn int UHCI_Initialise()
41  * \brief Called to initialise the UHCI Driver
42  */
43 int UHCI_Initialise(const char **Arguments)
44 {
45          int    i=0, id=-1;
46          int    ret;
47         
48         ENTER("");
49         
50         // Enumerate PCI Bus, getting a maximum of `MAX_CONTROLLERS` devices
51         while( (id = PCI_GetDeviceByClass(0x0C03, 0xFFFF, id)) >= 0 && i < MAX_CONTROLLERS )
52         {
53                 tUHCI_Controller        *cinfo = &gUHCI_Controllers[i];
54                 // NOTE: Check "protocol" from PCI?
55                 
56                 cinfo->PciId = id;
57                 // Assign a port range (BAR4, Reserve 32 ports)
58                 cinfo->IOBase = PCI_GetBAR(id, 4);
59                 if( !(cinfo->IOBase & 1) ) {
60                         Log_Warning("UHCI", "MMIO is not supported");
61                         continue ;
62                 }
63                 cinfo->IRQNum = PCI_GetIRQ(id);
64                 
65                 Log_Debug("UHCI", "Controller PCI #%i: IO Base = 0x%x, IRQ %i",
66                         id, cinfo->IOBase, cinfo->IRQNum);
67                 
68                 IRQ_AddHandler(cinfo->IRQNum, UHCI_InterruptHandler, cinfo);
69         
70                 // Initialise Host
71                 ret = UHCI_Int_InitHost(&gUHCI_Controllers[i]);
72                 // Detect an error
73                 if(ret != 0) {
74                         LEAVE('i', ret);
75                         return ret;
76                 }
77                 
78                 USB_RegisterHost(&gUHCI_HostDef, cinfo);
79
80                 i ++;
81         }
82         if(i == MAX_CONTROLLERS) {
83                 Log_Warning("UHCI", "Over "EXPAND_STR(MAX_CONTROLLERS)" UHCI controllers detected, ignoring rest");
84         }
85         LEAVE('i', MODULE_ERR_OK);
86         return MODULE_ERR_OK;
87 }
88
89 /**
90  * \fn void UHCI_Cleanup()
91  * \brief Called just before module is unloaded
92  */
93 void UHCI_Cleanup()
94 {
95 }
96
97 tUHCI_TD *UHCI_int_AllocateTD(tUHCI_Controller *Cont)
98 {
99          int    i;
100         for(i = 0; i < NUM_TDs; i ++)
101         {
102                 if(gaUHCI_TDPool[i].Link == 0) {
103                         gaUHCI_TDPool[i].Link = 1;
104                         return &gaUHCI_TDPool[i];
105                 }
106         }
107         return NULL;
108 }
109
110 void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_TD *TD)
111 {
112         Log_Warning("UHCI", "TODO: Implement AppendTD");
113 }
114
115 /**
116  * \brief Send a transaction to the USB bus
117  * \param Cont  Controller pointer
118  * \param Addr  Function Address * 16 + Endpoint
119  * \param bTgl  Data toggle value
120  */
121 void *UHCI_int_SendTransaction(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, int bIOC, void *Data, size_t Length)
122 {
123         tUHCI_TD        *td;
124
125         if( Length > 0x400 )    return NULL;    // Controller allows up to 0x500, but USB doesn't
126
127         td = UHCI_int_AllocateTD(Cont);
128
129         td->Link = 1;
130         td->Control = (Length - 1) & 0x7FF;
131         td->Token  = ((Length - 1) & 0x7FF) << 21;
132         td->Token |= (bTgl & 1) << 19;
133         td->Token |= (Addr & 0xF) << 15;
134         td->Token |= ((Addr/16) & 0xFF) << 8;
135         td->Token |= Type;
136
137         // TODO: Ensure 32-bit paddr
138         if( ((tVAddr)Data & PAGE_SIZE) + Length > PAGE_SIZE ) {
139                 Log_Warning("UHCI", "TODO: Support non single page transfers");
140 //              td->BufferPointer = 
141                 return NULL;
142         }
143         else {
144                 td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
145         }
146
147         if( bIOC ) {
148 //              td->Control
149         }
150
151         UHCI_int_AppendTD(Cont, td);
152
153         return td;
154 }
155
156 void *UHCI_DataIN(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length)
157 {
158         return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x69, DataTgl, bIOC, Data, Length);
159 }
160
161 void *UHCI_DataOUT(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length)
162 {
163         return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0xE1, DataTgl, bIOC, Data, Length);
164 }
165
166 void *UHCI_SendSetup(void *Ptr, int Fcn, int Endpt, int DataTgl, int bIOC, void *Data, size_t Length)
167 {
168         return UHCI_int_SendTransaction(Ptr, Fcn*16+Endpt, 0x2D, DataTgl, bIOC, Data, Length);
169 }
170
171 // === INTERNAL FUNCTIONS ===
172 /**
173  * \fn int UHCI_Int_InitHost(tUCHI_Controller *Host)
174  * \brief Initialises a UHCI host controller
175  * \param Host  Pointer - Host to initialise
176  */
177 int UHCI_Int_InitHost(tUHCI_Controller *Host)
178 {
179         ENTER("pHost", Host);
180
181         outw( Host->IOBase + USBCMD, 4 );       // GRESET
182         Time_Delay(10);
183         // TODO: Wait for at least 10ms
184         outw( Host->IOBase + USBCMD, 0 );       // GRESET
185         
186         // Allocate Frame List
187         // - 1 Page, 32-bit address
188         // - 1 page = 1024  4 byte entries
189         Host->FrameList = (void *) MM_AllocDMA(1, 32, &Host->PhysFrameList);
190         if( !Host->FrameList ) {
191                 Log_Warning("UHCI", "Unable to allocate frame list, aborting");
192                 LEAVE('i', -1);
193                 return -1;
194         }
195         LOG("Allocated frame list 0x%x (0x%x)", Host->FrameList, Host->PhysFrameList);
196         memsetd( Host->FrameList, 1, 1024 );    // Clear List (Disabling all entries)
197         
198         //! \todo Properly fill frame list
199         
200         // Set frame length to 1 ms
201         outb( Host->IOBase + SOFMOD, 64 );
202         
203         // Set Frame List
204         outd( Host->IOBase + FLBASEADD, Host->PhysFrameList );
205         outw( Host->IOBase + FRNUM, 0 );
206         
207         // Enable Interrupts
208         outw( Host->IOBase + USBINTR, 0x000F );
209         PCI_ConfigWrite( Host->PciId, 0xC0, 2, 0x2000 );
210
211         outw( Host->IOBase + USBCMD, 0x0001 );
212
213         LEAVE('i', 0);
214         return 0;
215 }
216
217 void UHCI_CheckPortUpdate(tUHCI_Controller *Host)
218 {
219         // Enable ports
220         for( int i = 0; i < 2; i ++ )
221         {
222                  int    port = Host->IOBase + PORTSC1 + i*2;
223                 // Check for port change
224                 if( !(inw(port) & 0x0002) )     continue;
225                 outw(port, 0x0002);
226                 
227                 // Check if the port is connected
228                 if( !(inw(port) & 1) )
229                 {
230                         // TODO: Tell the USB code it's gone?
231                         continue;
232                 }
233                 else
234                 {
235                         LOG("Port %i has something", i);
236                         // Reset port (set bit 9)
237                         outw( port, 0x0100 );
238                         Time_Delay(50); // 50ms delay
239                         outw( port, inw(port) & ~0x0100 );
240                         // Enable port
241                         Time_Delay(50); // 50ms delay
242                         outw( port, inw(port) & 0x0004 );
243                 }
244         }
245 }
246
247 void UHCI_InterruptHandler(int IRQ, void *Ptr)
248 {
249         Log_Debug("UHCI", "UHIC Interrupt");
250 }

UCC git Repository :: git.ucc.asn.au