Usermode/AxWin4 - Added text rendering (very hacky using VGA font)
[tpg/acess2.git] / KernelLand / Modules / Interfaces / UDI / trans / bus_pci.c
1 /*
2  * Acess2 UDI Layer
3  * - By John Hodge (thePowersGang)
4  *
5  * trans/bus_pci.c
6  * - PCI Bus Driver
7  */
8 #define DEBUG   0
9 #define UDI_PCI_VERSION 0x101
10 #include <udi.h>
11 #include <udi_physio.h>
12 #include <udi_pci.h>
13 #include <acess.h>
14 #include <drv_pci.h>    // acess
15 #include <udi_internal.h>
16 #include <trans_pci.h>
17
18 // === MACROS ===
19 /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */
20 #define DPT_SET_ATTR_BOOLEAN(attr, name, val)   \
21                 udi_strcpy((attr)->attr_name, (name)); \
22                 (attr)->attr_type = UDI_ATTR_BOOLEAN; \
23                 (attr)->attr_length = sizeof(udi_boolean_t); \
24                 UDI_ATTR32_SET((attr)->attr_value, (val))
25
26 #define DPT_SET_ATTR32(attr, name, val) \
27                 udi_strcpy((attr)->attr_name, (name)); \
28                 (attr)->attr_type = UDI_ATTR_UBIT32; \
29                 (attr)->attr_length = sizeof(udi_ubit32_t); \
30                 UDI_ATTR32_SET((attr)->attr_value, (val))
31
32 #define DPT_SET_ATTR_ARRAY8(attr, name, val, len) \
33                 udi_strcpy((attr)->attr_name, (name)); \
34                 (attr)->attr_type = UDI_ATTR_ARRAY8; \
35                 (attr)->attr_length = (len); \
36                 udi_memcpy((attr)->attr_value, (val), (len))
37
38 #define DPT_SET_ATTR_STRING(attr, name, val, len) \
39                 udi_strcpy((attr)->attr_name, (name)); \
40                 (attr)->attr_type = UDI_ATTR_STRING; \
41                 (attr)->attr_length = (len); \
42                 udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len))
43
44 #define PCI_OPS_BRIDGE  1
45 #define PCI_OPS_IRQ     2
46
47 #define PCI_MAX_EVENT_CBS       8
48
49 // === TYPES ===
50 typedef struct
51 {
52         udi_init_context_t      init_context;
53         
54         tPCIDev cur_iter;
55 } pci_rdata_t;
56
57 typedef struct
58 {
59         udi_child_chan_context_t        child_chan_context;
60         
61         udi_channel_t   interrupt_channel;
62         struct {
63                 tPAddr  paddr;
64                 void    *vaddr;
65                 size_t  length;
66         } bars[6];
67
68          int    interrupt_handle;
69
70         udi_pio_handle_t        intr_preprocessing;
71         udi_intr_event_cb_t     *event_cbs[PCI_MAX_EVENT_CBS];
72         udi_index_t     event_cb_wr_ofs;
73         udi_index_t     event_cb_rd_ofs;
74          int    bIntrEnabled;
75 } pci_child_chan_context_t;
76
77 // === PROTOTYPES ===
78 void    pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
79 void    pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
80 void    pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
81 void    pci_final_cleanup_req(udi_mgmt_cb_t *cb);
82
83 void    pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb);
84 void    pci_unbind_req(udi_bus_bind_cb_t *cb);
85 void    pci_bind_req_op(udi_bus_bind_cb_t *cb);
86 void    pci_intr_attach_req(udi_intr_attach_cb_t *cb);
87 void    pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel);
88 void    pci_intr_detach_req(udi_intr_detach_cb_t *cb);
89
90 void    pci_intr_ch_event_ind(udi_channel_event_cb_t *cb);
91 void    pci_intr_event_rdy(udi_intr_event_cb_t *cb);
92 void    pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result);
93 void    pci_intr_handler(int irq, void *void_context);
94 void    pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result);
95
96 // - Hook to physio (UDI doesn't define these)
97  int    pci_pio_get_regset(udi_cb_t *gcb, udi_ubit32_t regset_idx, void **baseptr, size_t *lenptr);
98
99 // === CODE ===
100 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
101 {
102         pci_rdata_t     *rdata = UDI_GCB(cb)->context;
103         
104         switch(cb->meta_idx)
105         {
106         case 1: // mgmt
107                 break;
108         }
109
110         switch(resource_level)
111         {
112         case UDI_RESOURCES_CRITICAL:
113         case UDI_RESOURCES_LOW:
114         case UDI_RESOURCES_NORMAL:
115         case UDI_RESOURCES_PLENTIFUL:
116                 break;
117         }
118
119         // TODO: Initialise rdata
120         rdata->cur_iter = -1;
121
122         udi_usage_res(cb);
123 }
124 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
125 {
126         pci_rdata_t     *rdata = UDI_GCB(cb)->context;
127         switch(enumeration_level)
128         {
129         case UDI_ENUMERATE_START:
130         case UDI_ENUMERATE_START_RESCAN:
131                 rdata->cur_iter = -1;
132         case UDI_ENUMERATE_NEXT:
133                 // TODO: Filters
134                 if( (rdata->cur_iter = PCI_GetDeviceByClass(0,0, rdata->cur_iter)) == -1 )
135                 {
136                         udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
137                 }
138                 else
139                 {
140                         udi_instance_attr_list_t *attr_list = cb->attr_list;
141                         Uint16  ven, dev;
142                         Uint32  class;
143                         PCI_GetDeviceInfo(rdata->cur_iter, &ven, &dev, &class);
144                         Uint8   revision;
145                         PCI_GetDeviceVersion(rdata->cur_iter, &revision);
146                         Uint16  sven, sdev;
147                         PCI_GetDeviceSubsys(rdata->cur_iter, &sven, &sdev);
148
149                         udi_strcpy(attr_list->attr_name, "identifier");
150                         attr_list->attr_length = sprintf((char*)attr_list->attr_value,
151                                 "%04x%04x%02x%04x%04x",
152                                 ven, dev, revision, sven, sdev);
153                         attr_list ++;
154                         DPT_SET_ATTR_STRING(attr_list, "bus_type", "pci", 3);
155                         attr_list ++;
156                         DPT_SET_ATTR32(attr_list, "pci_vendor_id", ven);
157                         attr_list ++;
158                         DPT_SET_ATTR32(attr_list, "pci_device_id", dev);
159                         attr_list ++;
160                         
161                         DPT_SET_ATTR32(attr_list, "pci_baseclass", class >> 16);
162                         attr_list ++;
163                         DPT_SET_ATTR32(attr_list, "pci_base_class", class >> 16);       // E20010702.1
164                         attr_list ++;
165                         DPT_SET_ATTR32(attr_list, "pci_sub_class", (class >> 8) & 0xFF);
166                         attr_list ++;
167                         DPT_SET_ATTR32(attr_list, "pci_prog_if", (class >> 0) & 0xFF);
168                         attr_list ++;
169
170                         cb->attr_valid_length = attr_list - cb->attr_list;
171                         cb->child_ID = rdata->cur_iter;
172                         udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1);
173                 }
174                 break;
175         }
176 }
177 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
178 {
179         UNIMPLEMENTED();
180 }
181 void pci_final_cleanup_req(udi_mgmt_cb_t *cb)
182 {
183         UNIMPLEMENTED();
184 }
185
186 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb)
187 {
188         UNIMPLEMENTED();
189 }
190 void pci_bind_req(udi_bus_bind_cb_t *cb)
191 {
192         // TODO: "Lock" PCI device
193
194         // TODO: DMA constraints
195         udi_bus_bind_ack(cb, 0, UDI_DMA_LITTLE_ENDIAN, UDI_OK);
196 }
197 void pci_unbind_req(udi_bus_bind_cb_t *cb)
198 {
199         UNIMPLEMENTED();
200 }
201 void pci_intr_attach_req(udi_intr_attach_cb_t *cb)
202 {
203         pci_child_chan_context_t *context = UDI_GCB(cb)->context;
204
205         ASSERT(cb->interrupt_idx == 0); 
206
207         context->intr_preprocessing = cb->preprocessing_handle;
208         // Check if interrupt is already bound
209         if( !UDI_HANDLE_IS_NULL(context->interrupt_channel, udi_channel_t) )
210         {
211                 udi_intr_attach_ack(cb, UDI_OK);
212                 return ;
213         }
214         // Create a channel
215         udi_channel_spawn(pci_intr_attach_req__channel_spawned, UDI_GCB(cb),
216                 cb->gcb.channel, cb->interrupt_idx, PCI_OPS_IRQ, context);
217 }
218 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel)
219 {
220         udi_intr_attach_cb_t *cb = UDI_MCB(gcb, udi_intr_attach_cb_t);
221         pci_child_chan_context_t *context = UDI_GCB(cb)->context;
222
223         if( UDI_HANDLE_IS_NULL(new_channel, udi_channel_t) )
224         {
225                 // oops
226                 return ;
227         }       
228
229         context->interrupt_channel = new_channel;
230         
231         context->interrupt_handle = IRQ_AddHandler(
232                 PCI_GetIRQ(context->child_chan_context.child_ID),
233                 pci_intr_handler, context);
234
235         udi_intr_attach_ack(cb, UDI_OK);
236 }
237 void pci_intr_detach_req(udi_intr_detach_cb_t *cb)
238 {
239         UNIMPLEMENTED();
240 }
241
242 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb)
243 {
244         UNIMPLEMENTED();
245 }
246 void pci_intr_event_rdy(udi_intr_event_cb_t *cb)
247 {
248         pci_child_chan_context_t        *context = UDI_GCB(cb)->context;
249
250         ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
251         ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
252
253         LOG("Rd %i, Wr %i [WR %p{%p}]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb, cb->event_buf);
254         if( context->event_cbs[context->event_cb_wr_ofs] )
255         {
256                 // oops, overrun.
257                 return ;
258         }
259         context->event_cbs[context->event_cb_wr_ofs++] = cb;
260         if( context->event_cb_wr_ofs == PCI_MAX_EVENT_CBS )
261                 context->event_cb_wr_ofs = 0;
262         
263         // TODO: Fire once >= min_event_pend CBs are recieved
264         if( !context->bIntrEnabled )
265         {
266                 context->bIntrEnabled = 1;
267                 udi_pio_trans(pci_intr_event_rdy__irqs_enabled, NULL, context->intr_preprocessing, 0, NULL, NULL);
268         }
269 }
270 void pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result)
271 {
272         // Do nothing
273 }
274
275 void pci_intr_handler(int irq, void *void_context)
276 {
277         pci_child_chan_context_t *context = void_context;
278
279         LOG("irq=%i, context=%p", irq, context);
280
281         if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) {
282                 // Dropped
283                 return ;
284         }
285
286         ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
287         ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
288
289         udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs];
290         LOG("Rd %i, Wr %i [RD %p]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb);
291         context->event_cbs[context->event_cb_rd_ofs] = NULL;
292         context->event_cb_rd_ofs ++;
293         if( context->event_cb_rd_ofs == PCI_MAX_EVENT_CBS )
294                 context->event_cb_rd_ofs = 0;
295         ASSERT(cb);
296         ASSERT(cb->gcb.scratch);
297         
298         if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) )
299         {
300                 // TODO: Ensure region is an interrupt region
301                 udi_intr_event_ind(cb, 0);
302         }
303         else
304         {
305                 // Processing
306                 *(udi_ubit8_t*)(cb->gcb.scratch) = 0;
307                 // - no event info, so mem_ptr=NULL
308                 udi_pio_trans(pci_intr_handle__trans_done, UDI_GCB(cb),
309                         context->intr_preprocessing, 1, cb->event_buf, NULL);
310                 // V V V
311         }
312 }
313
314 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
315 {
316         udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t);
317         LOG("cb(%p)->event_buf=%p, new_buf=%p",
318                 cb, cb->event_buf, new_buf);
319         
320         // TODO: Buffers should not change
321         cb->event_buf = new_buf;
322         cb->intr_result = result;
323         
324         udi_ubit8_t     intr_status = *(udi_ubit8_t*)(gcb->scratch);
325         if( intr_status & UDI_INTR_UNCLAIMED )
326         {
327                 // Not claimed, next please.
328                 // NOTE: Same as no event in the acess model
329                 LOG("Unclaimed");
330                 pci_intr_event_rdy(cb);
331         }
332         else if( intr_status & UDI_INTR_NO_EVENT )
333         {
334                 // No event should be generated, return cb to pool
335                 // EVIL!
336                 pci_intr_event_rdy(cb);
337                 LOG("No event, return cb to pool");
338         }
339         else
340         {
341                 LOG("Inform driver");
342                 udi_intr_event_ind(cb, UDI_INTR_PREPROCESSED);  
343         }
344 }
345
346 // - physio hooks
347 udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit32_t ofs, udi_ubit8_t len,
348         void *data, bool isOutput)
349 {
350 //      LOG("child_ID=%i, regset_idx=%i,ofs=0x%x,len=%i,data=%p,isOutput=%b",
351 //              child_ID, regset_idx, ofs, len, data, isOutput);
352         tPCIDev pciid = child_ID;
353         // TODO: Cache child mappings   
354
355         switch(regset_idx)
356         {
357         case UDI_PCI_CONFIG_SPACE:
358                 // TODO:
359                 return UDI_STAT_NOT_SUPPORTED;
360         case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: {
361                 Uint32 bar = PCI_GetBAR(pciid, regset_idx);
362                 if(bar & 1)
363                 {
364                         // IO BAR
365                         bar &= ~3;
366                         #define _IO(fc, type) do {\
367                                 if( isOutput ) { \
368                                         /*LOG("out"#fc"(0x%x, 0x%x)",bar+ofs,*(type*)data);*/\
369                                         out##fc(bar+ofs, *(type*)data); \
370                                 } \
371                                 else { \
372                                         *(type*)data = in##fc(bar+ofs); \
373                                         /*LOG("in"#fc"(0x%x) = 0x%x",bar+ofs,*(type*)data);*/\
374                                 }\
375                                 } while(0)
376                         switch(len)
377                         {
378                         case UDI_PIO_1BYTE:     _IO(b, udi_ubit8_t);    return UDI_OK;
379                         case UDI_PIO_2BYTE:     _IO(w, udi_ubit16_t);   return UDI_OK;
380                         case UDI_PIO_4BYTE:     _IO(d, udi_ubit32_t);   return UDI_OK;
381                         //case UDI_PIO_8BYTE:   _IO(q, uint64_t);       return UDI_OK;
382                         default:
383                                 return UDI_STAT_NOT_SUPPORTED;
384                         }
385                         #undef _IO
386                 }
387                 else
388                 {
389                         // Memory BAR
390                         //Uint64 longbar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM);
391                         return UDI_STAT_NOT_SUPPORTED;
392                 }
393                 break; }
394         default:
395                 return UDI_STAT_NOT_UNDERSTOOD;
396         }
397 }
398
399 // === UDI Functions ===
400 udi_mgmt_ops_t  pci_mgmt_ops = {
401         pci_usage_ind,
402         pci_enumerate_req,
403         pci_devmgmt_req,
404         pci_final_cleanup_req
405 };
406 udi_ubit8_t     pci_mgmt_op_flags[4] = {0,0,0,0};
407 udi_bus_bridge_ops_t    pci_bridge_ops = {
408         pci_bridge_ch_event_ind,
409         pci_bind_req,
410         pci_unbind_req,
411         pci_intr_attach_req,
412         pci_intr_detach_req
413 };
414 udi_ubit8_t     pci_bridge_op_flags[5] = {0,0,0,0,0};
415 udi_intr_dispatcher_ops_t       pci_irq_ops = {
416         pci_intr_ch_event_ind,
417         pci_intr_event_rdy
418 };
419 udi_ubit8_t     pci_irq_ops_flags[2] = {0,0};
420 udi_primary_init_t      pci_pri_init = {
421         .mgmt_ops = &pci_mgmt_ops,
422         .mgmt_op_flags = pci_mgmt_op_flags,
423         .mgmt_scratch_requirement = 0,
424         .enumeration_attr_list_length = 7,
425         .rdata_size = sizeof(pci_rdata_t),
426         .child_data_size = 0,
427         .per_parent_paths = 0
428 };
429 udi_ops_init_t  pci_ops_list[] = {
430         {
431                 PCI_OPS_BRIDGE, 1, UDI_BUS_BRIDGE_OPS_NUM,
432                 sizeof(pci_child_chan_context_t),
433                 (udi_ops_vector_t*)&pci_bridge_ops,
434                 pci_bridge_op_flags
435         },
436         {
437                 PCI_OPS_IRQ, 1, UDI_BUS_INTR_DISPATCH_OPS_NUM,
438                 0,
439                 (udi_ops_vector_t*)&pci_irq_ops,
440                 pci_irq_ops_flags
441         },
442         {0}
443 };
444 udi_init_t      pci_init = {
445         .primary_init_info = &pci_pri_init,
446         .ops_init_list = pci_ops_list
447 };
448 const char      pci_udiprops[] =
449         "properties_version 0x101\0"
450         "message 1 Acess2 Kernel\0"
451         "message 2 John Hodge ([email protected])\0"
452         "message 3 Acess2 PCI Bus\0"
453         "supplier 1\0"
454         "contact 2\0"
455         "name 3\0"
456         "module acess_pci\0"
457         "shortname acesspci\0"
458         "requires udi 0x101\0"
459         "provides udi_bridge 0x101\0"
460         "meta 1 udi_bridge\0"
461         "enumerates 4 0 100 1 bus_name string pci\0"
462         "region 0\0"
463         "child_bind_ops 1 0 1\0"
464         "";
465 size_t  pci_udiprops_size = sizeof(pci_udiprops);

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