3 * - By John Hodge (thePowersGang)
6 * - GIO UART translation (presents "uart" type GIO drivers as serial ports)
10 //#include <udi_gio.h>
13 #include <trans_uart.h>
14 #include <workqueue.h>
17 #define RX_SIZE 32 // Size of a read request
20 udi_init_context_t init_context;
23 tWorkqueue CBWorkQueue;
27 ACESSUART_CB_BIND = 1,
34 ACESSUART_META_GIO = 1,
38 void acessuart_pty_output(void *Handle, size_t Length, const void *Data);
41 void acessuart_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
43 udi_cb_t *gcb = UDI_GCB(cb);
44 rdata_t *rdata = gcb->context;
45 Workqueue_Init(&rdata->CBWorkQueue, "UDI UART TX", offsetof(udi_gio_xfer_cb_t, gcb.initiator_context));
48 void acessuart_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
52 void acessuart_final_cleanup_req(udi_mgmt_cb_t *cb)
57 void acessuart_channel_event_ind(udi_channel_event_cb_t *cb);
58 void acessuart_channel_event_ind__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_cb);
59 void acessuart_bind_ack(udi_gio_bind_cb_t *cb, udi_ubit32_t device_size_lo, udi_ubit32_t device_size_hi, udi_status_t status);
60 void acessuart_event_ind__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer);
62 void acessuart_channel_event_ind(udi_channel_event_cb_t *cb)
64 udi_cb_t *gcb = UDI_GCB(cb);
65 rdata_t *rdata = gcb->context;
69 case UDI_CHANNEL_CLOSED:
71 case UDI_CHANNEL_BOUND: {
72 rdata->active_cb = gcb;
74 udi_cb_alloc_batch(acessuart_channel_event_ind__tx_cbs_allocated, cb->params.parent_bound.bind_cb,
75 ACESSUART_CB_XFER, NUM_TX_CBS, FALSE, 0, UDI_NULL_BUF_PATH);
80 void acessuart_channel_event_ind__tx_cbs_allocated(udi_cb_t *gcb, udi_cb_t *first_cb)
82 rdata_t *rdata = gcb->context;
83 udi_gio_bind_cb_t *cb = UDI_MCB(gcb, udi_gio_bind_cb_t);
88 udi_cb_t *next = first_cb->initiator_context;
89 first_cb->initiator_context = NULL;
90 Workqueue_AddWork(&rdata->CBWorkQueue, first_cb);
95 // continued in acessuart_bind_ack
97 void acessuart_bind_ack(udi_gio_bind_cb_t *cb, udi_ubit32_t device_size_lo, udi_ubit32_t device_size_hi, udi_status_t status)
99 udi_cb_t *gcb = UDI_GCB(cb);
100 rdata_t *rdata = gcb->context;
101 udi_channel_event_cb_t *channel_cb = UDI_MCB(rdata->active_cb, udi_channel_event_cb_t);
103 if( device_size_lo != 0 || device_size_hi != 0 ) {
104 // Oops... binding failed. UARTS should not have a size
105 udi_channel_event_complete( channel_cb, UDI_STAT_NOT_UNDERSTOOD);
109 // bound, create PTY instance
110 rdata->PTYInstance = PTY_Create("serial#", rdata, acessuart_pty_output, NULL, NULL);
111 if( !rdata->PTYInstance ) {
112 udi_channel_event_complete(channel_cb, UDI_STAT_RESOURCE_UNAVAIL);
116 struct ptymode mode = {
117 .OutputMode = PTYBUFFMT_TEXT,
118 .InputMode = PTYIMODE_CANON|PTYIMODE_ECHO
120 struct ptydims dims = {
124 PTY_SetAttrib(rdata->PTYInstance, &dims, &mode, 0);
126 udi_channel_event_complete(channel_cb, UDI_OK);
128 void acessuart_unbind_ack(udi_gio_bind_cb_t *cb)
132 void acessuart_xfer_ack(udi_gio_xfer_cb_t *cb)
134 udi_cb_t *gcb = UDI_GCB(cb);
135 rdata_t *rdata = gcb->context;
136 if( cb->op == UDI_GIO_OP_WRITE ) {
137 // Write, no action required except returning the CB to the pool
138 udi_buf_free(cb->data_buf);
139 //cb->data_buf = NULL;
140 Workqueue_AddWork(&rdata->CBWorkQueue, cb);
142 else if( cb->op == UDI_GIO_OP_READ ) {
145 // TODO: Since this was a full ACK, request more?
148 // Well, that was unexpected
151 void acessuart_xfer_nak(udi_gio_xfer_cb_t *cb, udi_status_t status)
153 udi_cb_t *gcb = UDI_GCB(cb);
154 rdata_t *rdata = gcb->context;
155 if( cb->op == UDI_GIO_OP_READ && status == UDI_STAT_DATA_UNDERRUN )
157 udi_size_t len = cb->data_buf->buf_size;
160 udi_debug_printf("%s: no data read, rx buffer must be empty\n", __func__, len);
161 ASSERT(status != UDI_OK);
166 udi_buf_read(cb->data_buf, 0, len, tmp);
167 for( int i = 0; i < len; i ++ ) {
172 udi_debug_printf("%s: %i bytes '%.*s'\n", __func__, len, len, tmp);
173 PTY_SendInput(rdata->PTYInstance, tmp, len);
176 udi_buf_free(cb->data_buf);
178 // if status == OK, then all bytes we requested were read.
179 // - In which case, we want to request more
180 if( status == UDI_OK ) {
181 UDI_BUF_ALLOC(acessuart_event_ind__buf_allocated, gcb, NULL, RX_SIZE, UDI_NULL_BUF_PATH);
185 Workqueue_AddWork(&rdata->CBWorkQueue, cb);
191 void acessuart_event_ind(udi_gio_event_cb_t *cb)
193 udi_cb_t *gcb = UDI_GCB(cb);
194 rdata_t *rdata = gcb->context;
196 // ACK event before requesting read
197 udi_gio_event_res(cb);
199 // Begin read request
200 udi_gio_xfer_cb_t *read_cb = Workqueue_GetWork(&rdata->CBWorkQueue);
201 UDI_BUF_ALLOC(acessuart_event_ind__buf_allocated, UDI_GCB(read_cb), NULL, RX_SIZE, UDI_NULL_BUF_PATH);
203 void acessuart_event_ind__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer)
205 udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
207 cb->op = UDI_GIO_OP_READ;
208 cb->tr_params = NULL;
209 cb->data_buf = buffer;
211 udi_gio_xfer_req(cb);
212 // Continued in acessuart_xfer_ack/nak
216 void acessuart_pty_output(void *Handle, size_t Length, const void *Data);
217 void acessuart_pty_output__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer);
219 void acessuart_pty_output(void *Handle, size_t Length, const void *Data)
221 LOG("Output '%.*s'", Length, Data);
223 rdata_t *rdata = Handle;
224 udi_gio_xfer_cb_t *cb = Workqueue_GetWork(&rdata->CBWorkQueue);
225 udi_cb_t *gcb = UDI_GCB(cb);
227 UDI_BUF_ALLOC(acessuart_pty_output__buf_allocated, gcb, Data, Length, UDI_NULL_BUF_PATH);
228 // don't bother waiting for tx to complete, workqueue will block when everything is in use
229 // - And once buf_alloc returns, the data is copied
231 void acessuart_pty_output__buf_allocated(udi_cb_t *gcb, udi_buf_t *buffer)
233 //rdata_t *rdata = gcb->context;
234 LOG("buffer = %p\n", buffer);
235 udi_gio_xfer_cb_t *cb = UDI_MCB(gcb, udi_gio_xfer_cb_t);
237 cb->op = UDI_GIO_OP_WRITE;
238 cb->tr_params = NULL;
239 cb->data_buf = buffer;
241 udi_gio_xfer_req(cb);
245 // --------------------------------------------------------------------
246 udi_mgmt_ops_t acessuart_mgmt_ops = {
248 udi_enumerate_no_children,
249 acessuart_devmgmt_req,
250 acessuart_final_cleanup_req
252 udi_ubit8_t acessuart_mgmt_ops_flags[4] = {0,0,0,0};
254 udi_primary_init_t acessuart_pri_init = {
255 .mgmt_ops = &acessuart_mgmt_ops,
256 .mgmt_op_flags = acessuart_mgmt_ops_flags,
257 .mgmt_scratch_requirement = 0,
258 .enumeration_attr_list_length = 0,
259 .rdata_size = sizeof(rdata_t),
260 .child_data_size = 0,
261 .per_parent_paths = 0
264 udi_gio_client_ops_t acessuart_gio_ops = {
265 acessuart_channel_event_ind,
267 acessuart_unbind_ack,
272 udi_ubit8_t acessuart_gio_op_flags[7] = {0};
274 udi_ops_init_t acessuart_ops_list[] = {
276 ACESSUART_OPS_GIO, ACESSUART_META_GIO, UDI_GIO_CLIENT_OPS_NUM,
277 0, (udi_ops_vector_t*)&acessuart_gio_ops, acessuart_gio_op_flags
281 udi_cb_init_t acessuart_cb_init_list[] = {
282 {ACESSUART_CB_BIND, ACESSUART_META_GIO, UDI_GIO_BIND_CB_NUM, 0, 0,NULL},
283 {ACESSUART_CB_XFER, ACESSUART_META_GIO, UDI_GIO_XFER_CB_NUM, 0, 0,NULL},
286 const udi_init_t acessuart_init = {
287 .primary_init_info = &acessuart_pri_init,
288 .ops_init_list = acessuart_ops_list,
289 .cb_init_list = acessuart_cb_init_list,
291 const char acessuart_udiprops[] =
292 "properties_version 0x101\0"
293 "message 1 Acess2 Kernel\0"
295 "message 3 Acess2 UART\0"
299 "module acess_uart\0"
300 "shortname acessuart\0"
301 "requires udi 0x101\0"
302 "requires udi_gio 0x101\0"
305 "device 101 1 gio_type string uart\0"
306 "parent_bind_ops 1 0 1 1\0"
308 size_t acessuart_udiprops_size = sizeof(acessuart_udiprops);