3 * - By John Hodge (thePowersGang)
9 #include <udi_physio.h>
12 #include <drv_pci.h> // acess
13 #include <udi_internal.h>
14 #include <trans_pci.h>
17 /* Copied from http://projectudi.cvs.sourceforge.net/viewvc/projectudi/udiref/driver/udi_dpt/udi_dpt.h */
18 #define DPT_SET_ATTR_BOOLEAN(attr, name, val) \
19 udi_strcpy((attr)->attr_name, (name)); \
20 (attr)->attr_type = UDI_ATTR_BOOLEAN; \
21 (attr)->attr_length = sizeof(udi_boolean_t); \
22 UDI_ATTR32_SET((attr)->attr_value, (val))
24 #define DPT_SET_ATTR32(attr, name, val) \
25 udi_strcpy((attr)->attr_name, (name)); \
26 (attr)->attr_type = UDI_ATTR_UBIT32; \
27 (attr)->attr_length = sizeof(udi_ubit32_t); \
28 UDI_ATTR32_SET((attr)->attr_value, (val))
30 #define DPT_SET_ATTR_ARRAY8(attr, name, val, len) \
31 udi_strcpy((attr)->attr_name, (name)); \
32 (attr)->attr_type = UDI_ATTR_ARRAY8; \
33 (attr)->attr_length = (len); \
34 udi_memcpy((attr)->attr_value, (val), (len))
36 #define DPT_SET_ATTR_STRING(attr, name, val, len) \
37 udi_strcpy((attr)->attr_name, (name)); \
38 (attr)->attr_type = UDI_ATTR_STRING; \
39 (attr)->attr_length = (len); \
40 udi_strncpy_rtrim((char *)(attr)->attr_value, (val), (len))
42 #define PCI_OPS_BRIDGE 1
45 #define PCI_MAX_EVENT_CBS 8
50 udi_init_context_t init_context;
57 udi_child_chan_context_t child_chan_context;
59 udi_channel_t interrupt_channel;
68 udi_pio_handle_t intr_preprocessing;
69 udi_intr_event_cb_t *event_cbs[PCI_MAX_EVENT_CBS];
72 } pci_child_chan_context_t;
75 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level);
76 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level);
77 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID);
78 void pci_final_cleanup_req(udi_mgmt_cb_t *cb);
80 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb);
81 void pci_unbind_req(udi_bus_bind_cb_t *cb);
82 void pci_bind_req_op(udi_bus_bind_cb_t *cb);
83 void pci_intr_attach_req(udi_intr_attach_cb_t *cb);
84 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel);
85 void pci_intr_detach_req(udi_intr_detach_cb_t *cb);
87 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb);
88 void pci_intr_event_rdy(udi_intr_event_cb_t *cb);
89 void pci_intr_handler(int irq, void *void_context);
90 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result);
92 // - Hook to physio (UDI doesn't define these)
93 int pci_pio_get_regset(udi_cb_t *gcb, udi_ubit32_t regset_idx, void **baseptr, size_t *lenptr);
96 void pci_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
98 pci_rdata_t *rdata = UDI_GCB(cb)->context;
106 switch(resource_level)
108 case UDI_RESOURCES_CRITICAL:
109 case UDI_RESOURCES_LOW:
110 case UDI_RESOURCES_NORMAL:
111 case UDI_RESOURCES_PLENTIFUL:
115 // TODO: Initialise rdata
116 rdata->cur_iter = -1;
120 void pci_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
122 pci_rdata_t *rdata = UDI_GCB(cb)->context;
123 switch(enumeration_level)
125 case UDI_ENUMERATE_START:
126 case UDI_ENUMERATE_START_RESCAN:
127 rdata->cur_iter = -1;
128 case UDI_ENUMERATE_NEXT:
130 if( (rdata->cur_iter = PCI_GetDeviceByClass(0,0, rdata->cur_iter)) == -1 )
132 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
136 udi_instance_attr_list_t *attr_list = cb->attr_list;
139 PCI_GetDeviceInfo(rdata->cur_iter, &ven, &dev, &class);
141 PCI_GetDeviceVersion(rdata->cur_iter, &revision);
143 PCI_GetDeviceSubsys(rdata->cur_iter, &sven, &sdev);
145 udi_strcpy(attr_list->attr_name, "identifier");
146 attr_list->attr_length = sprintf((char*)attr_list->attr_value,
147 "%04x%04x%02x%04x%04x",
148 ven, dev, revision, sven, sdev);
150 DPT_SET_ATTR_STRING(attr_list, "bus_type", "pci", 3);
152 DPT_SET_ATTR32(attr_list, "pci_vendor_id", ven);
154 DPT_SET_ATTR32(attr_list, "pci_device_id", dev);
157 cb->attr_valid_length = attr_list - cb->attr_list;
158 cb->child_ID = rdata->cur_iter;
159 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 1);
164 void pci_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
168 void pci_final_cleanup_req(udi_mgmt_cb_t *cb)
173 void pci_bridge_ch_event_ind(udi_channel_event_cb_t *cb)
177 void pci_bind_req(udi_bus_bind_cb_t *cb)
179 // TODO: "Lock" PCI device
181 // TODO: DMA constraints
182 udi_bus_bind_ack(cb, 0, UDI_DMA_LITTLE_ENDIAN, UDI_OK);
184 void pci_unbind_req(udi_bus_bind_cb_t *cb)
188 void pci_intr_attach_req(udi_intr_attach_cb_t *cb)
190 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
192 ASSERT(cb->interrupt_idx == 0);
194 context->intr_preprocessing = cb->preprocessing_handle;
195 // Check if interrupt is already bound
196 if( !UDI_HANDLE_IS_NULL(context->interrupt_channel, udi_channel_t) )
198 udi_intr_attach_ack(cb, UDI_OK);
202 udi_channel_spawn(pci_intr_attach_req__channel_spawned, UDI_GCB(cb),
203 cb->gcb.channel, cb->interrupt_idx, PCI_OPS_IRQ, context);
205 void pci_intr_attach_req__channel_spawned(udi_cb_t *gcb, udi_channel_t new_channel)
207 udi_intr_attach_cb_t *cb = UDI_MCB(gcb, udi_intr_attach_cb_t);
208 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
210 if( UDI_HANDLE_IS_NULL(new_channel, udi_channel_t) )
216 context->interrupt_channel = new_channel;
218 context->interrupt_handle = IRQ_AddHandler(
219 PCI_GetIRQ(context->child_chan_context.child_ID),
220 pci_intr_handler, new_channel);
222 udi_intr_attach_ack(cb, UDI_OK);
224 void pci_intr_detach_req(udi_intr_detach_cb_t *cb)
229 void pci_intr_ch_event_ind(udi_channel_event_cb_t *cb)
233 void pci_intr_event_rdy(udi_intr_event_cb_t *cb)
235 pci_child_chan_context_t *context = UDI_GCB(cb)->context;
236 if( context->event_cbs[context->event_cb_wr_ofs] )
241 context->event_cbs[context->event_cb_wr_ofs++] = cb;
242 if( context->event_cb_wr_ofs == PCI_MAX_EVENT_CBS )
243 context->event_cb_wr_ofs = 0;
246 void pci_intr_handler(int irq, void *void_context)
248 pci_child_chan_context_t *context = void_context;
250 if( context->event_cb_rd_ofs == context->event_cb_wr_ofs ) {
255 udi_intr_event_cb_t *cb = context->event_cbs[context->event_cb_rd_ofs];
256 context->event_cbs[context->event_cb_rd_ofs] = NULL;
257 context->event_cb_rd_ofs ++;
258 if( context->event_cb_rd_ofs == PCI_MAX_EVENT_CBS )
259 context->event_cb_rd_ofs = 0;
261 if( UDI_HANDLE_IS_NULL(context->intr_preprocessing, udi_pio_handle_t) )
263 udi_intr_event_ind(cb, 0);
268 // - no event info, so mem_ptr=NULL
269 udi_pio_trans(pci_intr_handle__trans_done, UDI_GCB(cb),
270 context->intr_preprocessing, 1, cb->event_buf, NULL);
274 void pci_intr_handle__trans_done(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
276 udi_intr_event_cb_t *cb = UDI_MCB(gcb, udi_intr_event_cb_t);
278 cb->intr_result = result;
280 udi_intr_event_ind(cb, UDI_INTR_PREPROCESSED);
284 udi_status_t pci_pio_do_io(uint32_t child_ID, udi_ubit32_t regset_idx, udi_ubit32_t ofs, udi_ubit8_t len,
285 void *data, bool isOutput)
287 tPCIDev pciid = child_ID;
288 // TODO: Cache child mappings
292 case UDI_PCI_CONFIG_SPACE:
294 return UDI_STAT_NOT_SUPPORTED;
295 case UDI_PCI_BAR_0 ... UDI_PCI_BAR_5: {
296 Uint64 bar = PCI_GetBAR(pciid, regset_idx);
301 #define _IO(fc, type) do {\
302 if( isOutput ) out##fc(bar+ofs, *(type*)data); \
303 else *(type*)data = in##fc(bar+ofs); \
307 case UDI_PIO_1BYTE: _IO(b, udi_ubit8_t); return UDI_OK;
308 case UDI_PIO_2BYTE: _IO(w, udi_ubit16_t); return UDI_OK;
309 case UDI_PIO_4BYTE: _IO(d, udi_ubit32_t); return UDI_OK;
310 //case UDI_PIO_8BYTE: _IO(q, uint64_t); return UDI_OK;
312 return UDI_STAT_NOT_SUPPORTED;
319 bar = PCI_GetValidBAR(pciid, regset_idx, PCI_BARTYPE_MEM);
320 return UDI_STAT_NOT_SUPPORTED;
324 return UDI_STAT_NOT_UNDERSTOOD;
328 // === UDI Functions ===
329 udi_mgmt_ops_t pci_mgmt_ops = {
333 pci_final_cleanup_req
335 udi_ubit8_t pci_mgmt_op_flags[4] = {0,0,0,0};
336 udi_bus_bridge_ops_t pci_bridge_ops = {
337 pci_bridge_ch_event_ind,
343 udi_ubit8_t pci_bridge_op_flags[5] = {0,0,0,0,0};
344 udi_intr_dispatcher_ops_t pci_irq_ops = {
345 pci_intr_ch_event_ind,
348 udi_ubit8_t pci_irq_ops_flags[2] = {0,0};
349 udi_primary_init_t pci_pri_init = {
350 .mgmt_ops = &pci_mgmt_ops,
351 .mgmt_op_flags = pci_mgmt_op_flags,
352 .mgmt_scratch_requirement = 0,
353 .enumeration_attr_list_length = 4,
354 .rdata_size = sizeof(pci_rdata_t),
355 .child_data_size = 0,
356 .per_parent_paths = 0
358 udi_ops_init_t pci_ops_list[] = {
360 PCI_OPS_BRIDGE, 1, UDI_BUS_BRIDGE_OPS_NUM,
361 sizeof(pci_child_chan_context_t),
362 (udi_ops_vector_t*)&pci_bridge_ops,
366 PCI_OPS_IRQ, 1, UDI_BUS_INTR_DISPATCH_OPS_NUM,
368 (udi_ops_vector_t*)&pci_irq_ops,
373 udi_init_t pci_init = {
374 .primary_init_info = &pci_pri_init,
375 .ops_init_list = pci_ops_list
377 const char pci_udiprops[] =
378 "properties_version 0x101\0"
379 "message 1 Acess2 Kernel\0"
381 "message 3 Acess2 PCI Bus\0"
386 "shortname acesspci\0"
387 "requires udi 0x101\0"
388 "provides udi_bridge 0x101\0"
389 "meta 1 udi_bridge\0"
390 "enumerates 4 0 100 1 bus_name string pci\0"
392 "child_bind_ops 1 0 1\0"
394 size_t pci_udiprops_size = sizeof(pci_udiprops);