|
|
The pseudod driver defines parent channel operations that are almost identical to those defined by the udi_cmos driver. The difference is that when binding the channel, pseudo_bus_channel_event (the analog of cmos_bus_channel_event in the udi_cmos driver), allocates some memory to use as a transaction buffer.
/* *------------------------------------------------------------------------------ * Bus Bridge Interface Ops *------------------------------------------------------------------------------ */static void got_tx_mem(udi_cb_t *gcb, void *new_mem) { pseudo_region_data_t *rdata = gcb->context; rdata->tx_queue = new_mem;
udi_bus_bind_req(UDI_MCB(gcb, udi_bus_bind_cb_t));
}
static void pseudo_bus_channel_event(udi_channel_event_cb_t * cb) { udi_bus_bind_cb_t *bcb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
switch (cb->event) { case UDI_CHANNEL_BOUND: /* * Get our tx buffers. Let it allocate a bus bind cb */ UDI_GCB(bcb)->initiator_context = cb; udi_mem_alloc(got_tx_mem, UDI_GCB(bcb), PSEUDO_BUF_SZ, UDI_MEM_MOVABLE); break; default: udi_channel_event_complete(cb, UDI_OK); } }
static void pseudo_bus_bind_ack(udi_bus_bind_cb_t * bus_bind_cb, udi_dma_constraints_t dma_constraints, udi_ubit8_t preferred_endianness, udi_status_t status) { udi_channel_event_cb_t *channel_event_cb =
UDI_GCB(bus_bind_cb)->initiator_context; pseudo_region_data_t *rdata = UDI_GCB(bus_bind_cb)->context;
/* * As we don't have any hardware we can simply complete the * UDI_CHANNEL_BOUND event after stashing the bus_bind_cb for the * subsequent unbind() */ udi_dma_constraints_free(dma_constraints);
rdata->bus_bind_cb = bus_bind_cb;
udi_channel_event_complete(channel_event_cb, status); }
static void pseudo_bus_unbind_ack(udi_bus_bind_cb_t * bus_bind_cb) { udi_mgmt_cb_t *cb = bus_bind_cb->gcb.initiator_context; pseudo_region_data_t *rdata = UDI_GCB(bus_bind_cb)->context;
udi_cb_free(UDI_GCB(bus_bind_cb)); udi_mem_free(rdata->tx_queue);
udi_devmgmt_ack(cb, 0, UDI_OK); }
The difference in the code is that when pseudo_parent_channel_event switches on UDI_CHANNEL_BOUND, instead of executing udi_channel_event_complete, it issues a call to udi_mem_alloc(3udi) instead, with got_tx_mem as a callback:
udi_mem_alloc(got_tx_mem, UDI_GCB(bcb), PSEUDO_BUF_SZ, UDI_MEM_MOVABLE);
got_tx_mem issues the udi_channel_event_complete, after it stores the pointer to the new memory allocated by the environment in region data; the new memory pointer was passed back to the driver via a call to got_tx_mem, after the environment finished servicing the udi_mem_alloc.
udi_mem_alloc allocates a memory region solely for the use of the driver (it is not addressable by the device, as in direct memory access). This is used by the pseudod driver to imitate real I/O to and from a physical device; it is written and read by the driver subroutines for the child channel (see ``pseudod child channel operations''). It's passed a udi_bus_bind_cb_t(3udi) control block converted to a udi_cb_t control block by UDI_GCB(3udi), to preserve the call's context.
PSEUDO_BUF_SZ is the size of the buffer necessary (in bytes) to hold the test pattern; it was defined earlier in the code as 1024 (see ``pseudod.c region data structure'').
The UDI_MEM_MOVABLE flag allocates ``movable'' memory, which is required by the UDI specification for reference by control block fields or channel operation parameters.
See Memory Management and Memory Objects in the UDI Core Specification.
Finally, got_tx_mem copies the memory pointer allocated by udi_mem_alloc to a similarly-sized element in the region data structure, and requests the bind operation.
The acknowledgement of the bind operation, pseudo_bus_bind_ack, is identical to the routine used in the udi_cmos driver, cmos_bus_bind_ack.
The unbind operation, pseudo_bus_unbind_ack, has one difference from
the cmos_bus_unbind_ack routine in the udi_cmos driver: it
must free the memory pointed to by the region data structure before closing
the channel.
It does this with a call to
udi_mem_free(3udi),
using the pointer to the memory block (rdata->tx_queue
)
as the argument.
The remainder of these routines are identical to the similarly named routines for the udi_cmos driver, defined under ``udi_cmos parent channel operations''; refer back to that section for descriptions.