3 * - By John Hodge (thePowersGang)
9 #define UDI_VERSION 0x101
10 #define UDI_PHYSIO_VERSION 0x101
11 #define UDI_PCI_VERSION 0x101
13 #include <udi_physio.h>
16 #include <drv_pci.h> // acess
17 #include <udi_internal.h>
18 #include <trans_pci.h>
21 /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */
22 #define DPT_SET_ATTR_BOOLEAN(attr, name, val) \
23 udi_strcpy((attr)->attr_name, (name)); \
24 (attr)->attr_type = UDI_ATTR_BOOLEAN; \
25 (attr)->attr_length = sizeof(udi_boolean_t); \
26 UDI_ATTR32_SET((attr)->attr_value, (val))
28 #define DPT_SET_ATTR32(attr, name, val) \
29 udi_strcpy((attr)->attr_name, (name)); \
30 (attr)->attr_type = UDI_ATTR_UBIT32; \
31 (attr)->attr_length = sizeof(udi_ubit32_t); \
32 UDI_ATTR32_SET((attr)->attr_value, (val))
34 #define DPT_SET_ATTR_ARRAY8(attr, name, val, len) \
35 udi_strcpy((attr)->attr_name, (name)); \
36 (attr)->attr_type = UDI_ATTR_ARRAY8; \
37 (attr)->attr_length = (len); \
38 udi_memcpy((attr)->attr_value, (val), (len))
40 #define DPT_SET_ATTR_STRING(attr, name, val, len) \
41 udi_strcpy((attr)->attr_name, (name)); \
42 (attr)->attr_type = UDI_ATTR_STRING; \
43 (attr)->attr_length = (len); \
44 udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len))
46 #define PCI_OPS_BRIDGE 1
49 #define PCI_MAX_EVENT_CBS 8
54 udi_init_context_t init_context;
61 udi_child_chan_context_t child_chan_context;
63 udi_channel_t interrupt_channel;
72 udi_pio_handle_t intr_preprocessing;
73 udi_intr_event_cb_t *event_cbs[PCI_MAX_EVENT_CBS];
74 udi_index_t event_cb_wr_ofs;
75 udi_index_t event_cb_rd_ofs;
77 } pci_child_chan_context_t;
80 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
81 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
82 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
83 void pci_final_cleanup_req(udi_mgmt_cb_t *cb);
85 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb);
86 void pci_unbind_req(udi_bus_bind_cb_t *cb);
87 void pci_bind_req_op(udi_bus_bind_cb_t *cb);
88 void pci_intr_attach_req(udi_intr_attach_cb_t *cb);
89 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel);
90 void pci_intr_detach_req(udi_intr_detach_cb_t *cb);
92 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb);
93 void pci_intr_event_rdy(udi_intr_event_cb_t *cb);
94 void pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result);
95 void pci_intr_handler(int irq, void *void_context);
96 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result);
98 // - Hook to physio (UDI doesn't define these)
99 int pci_pio_get_regset(udi_cb_t *gcb, udi_ubit32_t regset_idx, void **baseptr, size_t *lenptr);
102 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
104 pci_rdata_t *rdata = UDI_GCB(cb)->context;
112 switch(resource_level)
114 case UDI_RESOURCES_CRITICAL:
115 case UDI_RESOURCES_LOW:
116 case UDI_RESOURCES_NORMAL:
117 case UDI_RESOURCES_PLENTIFUL:
121 // TODO: Initialise rdata
122 rdata->cur_iter = -1;
126 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
128 pci_rdata_t *rdata = UDI_GCB(cb)->context;
129 switch(enumeration_level)
131 case UDI_ENUMERATE_START:
132 case UDI_ENUMERATE_START_RESCAN:
133 rdata->cur_iter = -1;
134 case UDI_ENUMERATE_NEXT:
136 if( (rdata->cur_iter = PCI_GetDeviceByClass(0,0, rdata->cur_iter)) == -1 )
138 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
142 udi_instance_attr_list_t *attr_list = cb->attr_list;
145 PCI_GetDeviceInfo(rdata->cur_iter, &ven, &dev, &class);
147 PCI_GetDeviceVersion(rdata->cur_iter, &revision);
149 PCI_GetDeviceSubsys(rdata->cur_iter, &sven, &sdev);
151 udi_strcpy(attr_list->attr_name, "identifier");
152 attr_list->attr_length = sprintf((char*)attr_list->attr_value,
153 "%04x%04x%02x%04x%04x",
154 ven, dev, revision, sven, sdev);
156 DPT_SET_ATTR_STRING(attr_list, "bus_type", "pci", 3);
158 DPT_SET_ATTR32(attr_list, "pci_vendor_id", ven);
160 DPT_SET_ATTR32(attr_list, "pci_device_id", dev);
163 DPT_SET_ATTR32(attr_list, "pci_baseclass", class >> 16);
165 DPT_SET_ATTR32(attr_list, "pci_base_class", class >> 16); // E20010702.1
167 DPT_SET_ATTR32(attr_list, "pci_sub_class", (class >> 8) & 0xFF);
169 DPT_SET_ATTR32(attr_list, "pci_prog_if", (class >> 0) & 0xFF);
172 cb->attr_valid_length = attr_list - cb->attr_list;
173 cb->child_ID = rdata->cur_iter;
174 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1);
179 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
183 void pci_final_cleanup_req(udi_mgmt_cb_t *cb)
188 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb)
192 void pci_bind_req(udi_bus_bind_cb_t *cb)
194 // TODO: "Lock" PCI device
196 // TODO: DMA constraints
197 udi_bus_bind_ack(cb, 0, UDI_DMA_LITTLE_ENDIAN, UDI_OK);
199 void pci_unbind_req(udi_bus_bind_cb_t *cb)
203 void pci_intr_attach_req(udi_intr_attach_cb_t *cb)
205 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
207 ASSERT(cb->interrupt_idx == 0);
209 context->intr_preprocessing = cb->preprocessing_handle;
210 // Check if interrupt is already bound
211 if( !UDI_HANDLE_IS_NULL(context->interrupt_channel, udi_channel_t) )
213 udi_intr_attach_ack(cb, UDI_OK);
217 udi_channel_spawn(pci_intr_attach_req__channel_spawned, UDI_GCB(cb),
218 cb->gcb.channel, cb->interrupt_idx, PCI_OPS_IRQ, context);
220 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel)
222 udi_intr_attach_cb_t *cb = UDI_MCB(gcb, udi_intr_attach_cb_t);
223 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
225 if( UDI_HANDLE_IS_NULL(new_channel, udi_channel_t) )
231 context->interrupt_channel = new_channel;
233 context->interrupt_handle = IRQ_AddHandler(
234 PCI_GetIRQ(context->child_chan_context.child_ID),
235 pci_intr_handler, context);
237 udi_intr_attach_ack(cb, UDI_OK);
239 void pci_intr_detach_req(udi_intr_detach_cb_t *cb)
244 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb)
248 void pci_intr_event_rdy(udi_intr_event_cb_t *cb)
250 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
252 ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
253 ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
255 LOG("Rd %i, Wr %i [WR %p{%p}]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb, cb->event_buf);
256 if( context->event_cbs[context->event_cb_wr_ofs] )
261 context->event_cbs[context->event_cb_wr_ofs++] = cb;
262 if( context->event_cb_wr_ofs == PCI_MAX_EVENT_CBS )
263 context->event_cb_wr_ofs = 0;
265 // TODO: Fire once >= min_event_pend CBs are recieved
266 if( !context->bIntrEnabled )
268 context->bIntrEnabled = 1;
269 udi_pio_trans(pci_intr_event_rdy__irqs_enabled, NULL, context->intr_preprocessing, 0, NULL, NULL);
272 void pci_intr_event_rdy__irqs_enabled(udi_cb_t *gcb, udi_buf_t *newbuf, udi_status_t status, udi_ubit16_t result)
277 void pci_intr_handler(int irq, void *void_context)
279 pci_child_chan_context_t *context = void_context;
281 LOG("irq=%i, context=%p", irq, context);
283 if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) {
288 ASSERTC(context->event_cb_rd_ofs, <, PCI_MAX_EVENT_CBS);
289 ASSERTC(context->event_cb_wr_ofs, <, PCI_MAX_EVENT_CBS);
291 udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs];
292 LOG("Rd %i, Wr %i [RD %p]", context->event_cb_rd_ofs, context->event_cb_wr_ofs, cb);
293 context->event_cbs[context->event_cb_rd_ofs] = NULL;
294 context->event_cb_rd_ofs ++;
295 if( context->event_cb_rd_ofs == PCI_MAX_EVENT_CBS )
296 context->event_cb_rd_ofs = 0;
298 ASSERT(cb->gcb.scratch);
300 if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) )
302 // TODO: Ensure region is an interrupt region
303 udi_intr_event_ind(cb, 0);
308 *(udi_ubit8_t*)(cb->gcb.scratch) = 0;
309 // - no event info, so mem_ptr=NULL
310 udi_pio_trans(pci_intr_handle__trans_done, UDI_GCB(cb),
311 context->intr_preprocessing, 1, cb->event_buf, NULL);
316 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
318 udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t);
319 LOG("cb(%p)->event_buf=%p, new_buf=%p",
320 cb, cb->event_buf, new_buf);
322 // TODO: Buffers should not change
323 cb->event_buf = new_buf;
324 cb->intr_result = result;
326 udi_ubit8_t intr_status = *(udi_ubit8_t*)(gcb->scratch);
327 if( intr_status & UDI_INTR_UNCLAIMED )
329 // Not claimed, next please.
330 // NOTE: Same as no event in the acess model
332 pci_intr_event_rdy(cb);
334 else if( intr_status & UDI_INTR_NO_EVENT )
336 // No event should be generated, return cb to pool
338 pci_intr_event_rdy(cb);
339 LOG("No event, return cb to pool");
343 LOG("Inform driver");
344 udi_intr_event_ind(cb, UDI_INTR_PREPROCESSED);
349 udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit32_t ofs, udi_ubit8_t len,
350 void *data, bool isOutput)
352 // LOG("child_ID=%i, regset_idx=%i,ofs=0x%x,len=%i,data=%p,isOutput=%b",
353 // child_ID, regset_idx, ofs, len, data, isOutput);
354 tPCIDev pciid = child_ID;
355 // TODO: Cache child mappings
359 case UDI_PCI_CONFIG_SPACE:
361 return UDI_STAT_NOT_SUPPORTED;
362 case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: {
363 Uint32 bar = PCI_GetBAR(pciid, regset_idx);
368 #define _IO(fc, type) do {\
370 /*LOG("out"#fc"(0x%x, 0x%x)",bar+ofs,*(type*)data);*/\
371 out##fc(bar+ofs, *(type*)data); \
374 *(type*)data = in##fc(bar+ofs); \
375 /*LOG("in"#fc"(0x%x) = 0x%x",bar+ofs,*(type*)data);*/\
380 case UDI_PIO_1BYTE: _IO(b, udi_ubit8_t); return UDI_OK;
381 case UDI_PIO_2BYTE: _IO(w, udi_ubit16_t); return UDI_OK;
382 case UDI_PIO_4BYTE: _IO(d, udi_ubit32_t); return UDI_OK;
383 //case UDI_PIO_8BYTE: _IO(q, uint64_t); return UDI_OK;
385 return UDI_STAT_NOT_SUPPORTED;
392 //Uint64 longbar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM);
393 return UDI_STAT_NOT_SUPPORTED;
397 return UDI_STAT_NOT_UNDERSTOOD;
401 // === UDI Functions ===
402 udi_mgmt_ops_t pci_mgmt_ops = {
406 pci_final_cleanup_req
408 udi_ubit8_t pci_mgmt_op_flags[4] = {0,0,0,0};
409 udi_bus_bridge_ops_t pci_bridge_ops = {
410 pci_bridge_ch_event_ind,
416 udi_ubit8_t pci_bridge_op_flags[5] = {0,0,0,0,0};
417 udi_intr_dispatcher_ops_t pci_irq_ops = {
418 pci_intr_ch_event_ind,
421 udi_ubit8_t pci_irq_ops_flags[2] = {0,0};
422 udi_primary_init_t pci_pri_init = {
423 .mgmt_ops = &pci_mgmt_ops,
424 .mgmt_op_flags = pci_mgmt_op_flags,
425 .mgmt_scratch_requirement = 0,
426 .enumeration_attr_list_length = 7,
427 .rdata_size = sizeof(pci_rdata_t),
428 .child_data_size = 0,
429 .per_parent_paths = 0
431 udi_ops_init_t pci_ops_list[] = {
433 PCI_OPS_BRIDGE, 1, UDI_BUS_BRIDGE_OPS_NUM,
434 sizeof(pci_child_chan_context_t),
435 (udi_ops_vector_t*)&pci_bridge_ops,
439 PCI_OPS_IRQ, 1, UDI_BUS_INTR_DISPATCH_OPS_NUM,
441 (udi_ops_vector_t*)&pci_irq_ops,
446 udi_init_t pci_init = {
447 .primary_init_info = &pci_pri_init,
448 .ops_init_list = pci_ops_list
450 const char pci_udiprops[] =
451 "properties_version 0x101\0"
452 "message 1 Acess2 Kernel\0"
454 "message 3 Acess2 PCI Bus\0"
459 "shortname acesspci\0"
460 "requires udi 0x101\0"
461 "provides udi_bridge 0x101\0"
462 "meta 1 udi_bridge\0"
463 "enumerates 4 0 100 1 bus_name string pci\0"
465 "child_bind_ops 1 0 1\0"
467 size_t pci_udiprops_size = sizeof(pci_udiprops);