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

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