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

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