UDI Sample CMOS Driver Listing
Filename: udiprops.txt
1 # UDI driver properties for the CMOS RAM sample driver.
2
3 properties_version 0x095
4
5 ##
6 ## Identify ourselves.
7 ##
8
9 supplier 1
10 message 1 Project UDI
11 contact 2
12 message 2 http://www.sco.com/udi/participants.html
13 name 3
14 message 3 CMOS RAM Sample UDI Driver
15
16 shortname udi_cmos
17 release 2 alpha1.0rc3
18
19 ##
20 ## Describe supported devices.
21 ##
22
23 # Since this is a "System"-bus device, which is not self-identifying,
24 # we have to specify a default I/O address range with "config_choices".
25 # For PCI devices, there'd be no "config_choices" and the "device"
26 # declaration would include attributes like "pci_vendor_id".
27
28 device 10 2 bus_type string system
29 message 10 Motherboard CMOS RAM
30 config_choices 10 ioaddr1 ubit32 0x70 any iolen1 ubit32 2 only
31
32 ##
33 ## Declare the driver's module(s) and region types.
34 ## This driver has a single region in a single module.
35 ##
36
37 module udi_cmos
38 region 0
39
40 ##
41 ## Declare interface dependencies.
42 ##
43
44 requires udi 0x095
45 requires udi_physio 0x095
46 requires udi_gio 0x095
47 requires udi_bridge 0x095
48
49 ##
50 ## Describe metalanguage usage.
51 ##
52
53 meta 1 udi_gio # Generic I/O Metalanguage
54 meta 2 udi_bridge # Bus Bridge Metalanguage
55
56 child_bind_ops 1 0 1 # GIO meta, primary region, ops_index 1
57 parent_bind_ops 2 0 2 # Bridge meta, primary region, ops_index 2
58
59 ##
60 ## Build instructions (UDI drivers don't have makefiles!).
61 ##
62
63 compile_option -DCMOS_GIO_META=1 -DCMOS_BRIDGE_META=2
64 source_files udi_cmos.c
65
Filename: udi_cmos.c
1 /*
2 * ====================================================================
3 * File: udi_cmos.c
4 * Descr: UDI CMOS RAM Sample Driver
5 * --------------------------------------------------------------------
6 *
7 * Note: This driver does not actually use interrupts, but if it did,
8 * the code would look something like the DO_INTERRUPTS
9 * conditional code.
10 */
11
12 /*
13 * We must define these version symbols before including the header
14 * files, to indicate the interface versions we're using.
15 */
16 #define UDI_VERSION 0x095
17 #define UDI_PHYSIO_VERSION 0x095
18
19 #include <udi.h> /* Standard UDI Definitions */
20 #include <udi_physio.h> /* Physical I/O Extensions */
21
22 /*
23 * Region data structure for this driver.
24 */
25 typedef struct {
26 /* init_context is filled in by the environment: */
27 udi_init_context_t init_context;
28 udi_bus_bind_cb_t *bus_bind_cb;
29 /* PIO trans handles for reading and writing, respectively: */
30 udi_pio_handle_t trans_read;
31 udi_pio_handle_t trans_write;
32 } cmos_region_data_t;
33
34 /*
35 * Scratch structures for various control block types.
36 */
37 typedef struct {
38 udi_ubit8_t addr; /* CMOS device address */
39 udi_ubit8_t count; /* # bytes to transfer */
40 } cmos_gio_xfer_scratch_t;
41
42 /*
43 * GIO transfer scratch offsets for PIO trans list processing.
44 */
45 #define SCRATCH_ADDR offsetof(cmos_gio_xfer_scratch_t, addr)
46 #define SCRATCH_COUNT offsetof(cmos_gio_xfer_scratch_t, count)
47
48 /*
49 * CB indexes for each of the types of control blocks used.
50 */
51 #define GIO_BIND_CB_IDX 1
52 #define GIO_XFER_CB_IDX 2
53 #define GIO_EVENT_CB_IDX 3
54 #define BUS_BIND_CB_IDX 4
55 #if DO_INTERRUPTS
56 #define INTR_ATTACH_CB_IDX 5
57 #define INTR_EVENT_CB_IDX 6
58 #endif
59
60 /*
61 * Scratch sizes for each control block type.
62 */
63 #define GIO_BIND_SCRATCH 0
64 #define GIO_XFER_SCRATCH sizeof(cmos_gio_xfer_scratch_t)
65 #define GIO_EVENT_SCRATCH 0
66 #define BUS_BIND_SCRATCH 0
67 #if DO_INTERRUPTS
68 #define INTR_ATTACH_SCRATCH 0
69 #define INTR_EVENT_SCRATCH 0
70 #endif
71
72 /*
73 * Ops indexes for each of the entry point ops vectors used.
74 */
75 #define GIO_OPS_IDX 1
76 #define BUS_DEVICE_OPS_IDX 2
77 #if DO_INTERRUPTS
78 #define INTR_HANDLER_OPS_IDX 3
79 #endif
80
81 /*
82 * Driver entry points for the Management Metalanguage.
83 */
84 static udi_devmgmt_req_op_t cmos_devmgmt_req;
85 static udi_final_cleanup_req_op_t cmos_final_cleanup_req;
86
87 static const udi_mgmt_ops_t cmos_mgmt_ops = {
88 udi_static_usage,
89 udi_enumerate_no_children,
90 cmos_devmgmt_req,
91 cmos_final_cleanup_req
92 };
93
94 /*
95 * Driver "top-side" entry points for the GIO Metalanguage.
96 */
97
98 static udi_channel_event_ind_op_t cmos_child_channel_event;
99 static udi_gio_bind_req_op_t cmos_gio_bind_req;
100 static udi_gio_unbind_req_op_t cmos_gio_unbind_req;
101 static udi_gio_xfer_req_op_t cmos_gio_xfer_req;
102
103 static const udi_gio_provider_ops_t cmos_gio_provider_ops = {
104 cmos_child_channel_event,
105 cmos_gio_bind_req,
106 cmos_gio_unbind_req,
107 cmos_gio_xfer_req,
108 udi_gio_event_res_unused
109 };
110
111 /*
112 * Driver "bottom-side" entry points for the Bus Bridge Metalanguage.
113 */
114
115 static udi_channel_event_ind_op_t cmos_parent_channel_event;
116 static udi_bus_bind_ack_op_t cmos_bus_bind_ack;
117 static udi_bus_unbind_ack_op_t cmos_bus_unbind_ack;
118 #if DO_INTERRUPTS
119 static udi_intr_attach_ack_op_t cmos_intr_attach_ack;
120 static udi_intr_detach_ack_op_t cmos_intr_detach_ack;
121 #endif
122
123 static const udi_bus_device_ops_t cmos_bus_device_ops = {
124 cmos_parent_channel_event,
125 cmos_bus_bind_ack,
126 cmos_bus_unbind_ack,
127 #if DO_INTERRUPTS
128 cmos_intr_attach_ack,
129 cmos_intr_detach_ack
130 #else
131 udi_intr_attach_ack_unused,
132 udi_intr_detach_ack_unused
133 #endif
134 };
135
136 #if DO_INTERRUPTS
137 static udi_channel_event_ind_op_t cmos_intr_channel_event;
138 static udi_intr_event_ind_op_t cmos_intr_event_ind;
139
140 static const udi_intr_handler_ops_t cmos_intr_handler_ops = {
141 cmos_intr_channel_event,
142 cmos_intr_event_ind
143 };
144 #endif
145
146 /*
147 * PIO properties of the physical I/O registers on the CMOS device.
148 */
149 #define CMOS_REGSET 1 /* first (and only) register set */
150 #define CMOS_BASE 0 /* base address within this regset */
151 #define CMOS_LENGTH 2 /* two bytes worth of registers */
152 #define CMOS_PACE 5 /* wait 5 microseconds between accesses
153 * (not really need for this device,
154 * but illustrates use of pacing)
155 */
156
157 /*
158 * PIO offsets for various device registers, relative to the base of
159 * the device's register set.
160 */
161 #define CMOS_ADDR 0 /* address register */
162 #define CMOS_DATA 1 /* data register */
163
164 /*
165 * Other device properties.
166 */
167 #define CMOS_DEVSIZE 0x40 /* # data bytes supported by device */
168 #define CMOS_RDONLY_SZ 0x0E /* first 14 bytes are read-only */
169
170 /*
171 * PIO trans lists for access to the CMOS device.
172 */
173 static const udi_pio_trans_t cmos_trans_read[] = {
174 /* R0 <- SCRATCH_ADDR {offset into scratch of address} */
175 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_ADDR },
176 /* R1 <- address */
177 { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0,
178 UDI_PIO_1BYTE, UDI_PIO_R1 },
179 /* R0 <- SCRATCH_COUNT {offset into scratch of count} */
180 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_COUNT },
181 /* R2 <- count */
182 { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0,
183 UDI_PIO_1BYTE, UDI_PIO_R2 },
184 /* R0 <- 0 {current buffer offset} */
185 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, 0 },
186 /* begin main loop */
187 { UDI_PIO_LABEL, 0, 1 },
188 /* output address from R1 to address register */
189 { UDI_PIO_OUT+UDI_PIO_DIRECT+UDI_PIO_R1,
190 UDI_PIO_1BYTE, CMOS_ADDR },
191 /* input value from data register into next buffer location */
192 { UDI_PIO_IN+UDI_PIO_BUF+UDI_PIO_R0,
193 UDI_PIO_1BYTE, CMOS_DATA },
194 /* decrement count (in R2) */
195 { UDI_PIO_ADD_IMM+UDI_PIO_R2, UDI_PIO_1BYTE, (udi_ubit8_t)-1 },
196 /* if count is zero, we're done */
197 { UDI_PIO_CSKIP+UDI_PIO_R2, UDI_PIO_1BYTE, UDI_PIO_NZ },
198 { UDI_PIO_END, UDI_PIO_2BYTE, 0 },
199 /* increment address and buffer offset */
200 { UDI_PIO_ADD_IMM+UDI_PIO_R1, UDI_PIO_1BYTE, 1 },
201 { UDI_PIO_ADD_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 1 },
202 /* go back to main loop */
203 { UDI_PIO_BRANCH, 0, 1 }
204 };
205 static const udi_pio_trans_t cmos_trans_write[] = {
206 /* R0 <- SCRATCH_ADDR {offset into scratch of address} */
207 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_ADDR },
208 /* R1 <- address */
209 { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0,
210 UDI_PIO_1BYTE, UDI_PIO_R1 },
211 /* R0 <- SCRATCH_COUNT {offset into scratch of count} */
212 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, SCRATCH_COUNT },
213 /* R2 <- count */
214 { UDI_PIO_LOAD+UDI_PIO_SCRATCH+UDI_PIO_R0,
215 UDI_PIO_1BYTE, UDI_PIO_R2 },
216 /* R0 <- 0 {current buffer offset} */
217 { UDI_PIO_LOAD_IMM+UDI_PIO_R0, UDI_PIO_2BYTE, 0 },
218 /* begin main loop */
219 { UDI_PIO_LABEL, 0, 1 },
220 /* output address from R1 to address register */
221 { UDI_PIO_OUT+UDI_PIO_DIRECT+UDI_PIO_R1,
222 UDI_PIO_1BYTE, CMOS_ADDR },
223 /* output value from next buffer location to data register */
224 { UDI_PIO_OUT+UDI_PIO_BUF+UDI_PIO_R0,
225 UDI_PIO_1BYTE, CMOS_DATA },
226 /* decrement count (in R2) */
227 { UDI_PIO_ADD_IMM+UDI_PIO_R2, UDI_PIO_1BYTE, (udi_ubit8_t)-1 },
228 /* if count is zero, we're done */
229 { UDI_PIO_CSKIP+UDI_PIO_R2, UDI_PIO_1BYTE, UDI_PIO_NZ },
230 { UDI_PIO_END, UDI_PIO_2BYTE, 0 },
231 /* increment address and buffer offset */
232 { UDI_PIO_ADD_IMM+UDI_PIO_R1, UDI_PIO_1BYTE, 1 },
233 { UDI_PIO_ADD_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 1 },
234 /* go back to main loop */
235 { UDI_PIO_BRANCH, 0, 1 }
236 };
237
238 /*
239 * --------------------------------------------------------------------
240 * Management operations init section:
241 * --------------------------------------------------------------------
242 */
243 static const udi_primary_init_t udi_cmos_primary_init_info = {
244 &cmos_mgmt_ops,
245 0, /* mgmt_scratch_size */
246 0, /* no children, so no enumeration */
247 sizeof(cmos_region_data_t)
248 };
249
250 /*
251 * --------------------------------------------------------------------
252 * Meta operations init section:
253 * --------------------------------------------------------------------
254 */
255 static const udi_ops_init_t udi_cmos_ops_init_list[] = {
256 {
257 GIO_OPS_IDX,
258 CMOS_GIO_META, /* meta index
259 * [from udiprops.txt] */
260 UDI_GIO_PROVIDER_OPS_NUM,
261 0, /* no channel context */
262 (udi_ops_vector_t *)&cmos_gio_provider_ops
263 },
264 {
265 BUS_DEVICE_OPS_IDX,
266 CMOS_BRIDGE_META, /* meta index
267 * [from udiprops.txt] */
268 UDI_BUS_DEVICE_OPS_NUM,
269 0, /* no channel context */
270 (udi_ops_vector_t *)&cmos_bus_device_ops
271 },
272 #if DO_INTERRUPTS
273 {
274 INTR_HANDLER_OPS_IDX,
275 CMOS_BRIDGE_META, /* meta index
276 * [from udiprops.txt] */
277 UDI_BUS_INTR_HANDLER_OPS_NUM,
278 0, /* no channel context */
279 (udi_ops_vector_t *)&cmos_intr_handler_ops
280 },
281 #endif /* DO_INTERRUPTS */
282 {
283 0 /* Terminator */
284 }
285 };
286
287 /*
288 * --------------------------------------------------------------------
289 * Control Block init section:
290 * --------------------------------------------------------------------
291 */
292 static const udi_cb_init_t udi_cmos_cb_init_list[] = {
293 {
294 GIO_BIND_CB_IDX, /* GIO Bind CB */
295 CMOS_GIO_META, /* from udiprops.txt */
296 UDI_GIO_BIND_CB_NUM, /* meta cb_num */
297 GIO_BIND_SCRATCH, /* scratch requirement */
298 0, /* inline size */
299 NULL /* inline layout */
300 },
301 {
302 GIO_XFER_CB_IDX, /* GIO Xfer CB */
303 CMOS_GIO_META, /* from udiprops.txt */
304 UDI_GIO_XFER_CB_NUM, /* meta cb_num */
305 GIO_XFER_SCRATCH, /* scratch requirement */
306 0, /* inline size */
307 NULL /* inline layout */
308 },
309 {
310 GIO_EVENT_CB_IDX, /* GIO Event CB */
311 CMOS_GIO_META, /* from udiprops.txt */
312 UDI_GIO_EVENT_CB_NUM, /* meta cb_num */
313 GIO_EVENT_SCRATCH, /* scratch requirement */
314 0, /* inline size */
315 NULL /* inline layout */
316 },
317 {
318 BUS_BIND_CB_IDX, /* Bridge Bind CB */
319 CMOS_BRIDGE_META, /* from udiprops.txt */
320 UDI_BUS_BIND_CB_NUM, /* meta cb_num */
321 BUS_BIND_SCRATCH, /* scratch requirement */
322 0, /* inline size */
323 NULL /* inline layout */
324 },
325 #if DO_INTERRUPTS
326 {
327 INTR_ATTACH_CB_IDX, /* Interrupt Attach CB */
328 CMOS_BRIDGE_META, /* from udiprops.txt */
329 UDI_BUS_INTR_ATTACH_CB_NUM, /* meta cb_num */
330 INTR_ATTACH_SCRATCH, /* scratch requirement */
331 0, /* inline size */
332 NULL /* inline layout */
333 },
334 {
335 INTR_EVENT_CB_IDX, /* Interrupt Event CB */
336 CMOS_BRIDGE_META, /* from udiprops.txt */
337 UDI_BUS_INTR_EVENT_CB_NUM, /* meta cb_num */
338 INTR_EVENT_SCRATCH, /* scratch requirement */
339 0, /* inline size */
340 NULL /* inline layout */
341 },
342 #endif /* DO_INTERRUPTS */
343 {
344 0 /* Terminator */
345 }
346 };
347
348 const udi_init_t udi_init_info = {
349 &udi_cmos_primary_init_info,
350 NULL, /* secondary_init_list */
351 udi_cmos_ops_init_list,
352 udi_cmos_cb_init_list,
353 NULL, /* gcb_init_list */
354 NULL /* cb_select_list */
355 };
356
357 /*
358 * --------------------------------------------------------------------
359 *
360 * --------------------------------------------------------------------
361 */
362
363 static void cmos_bind_to_parent_1(udi_cb_t *, udi_cb_t *);
364
365 static void
366 cmos_parent_channel_event(udi_channel_event_cb_t *channel_event_cb)
367 {
368 switch (channel_event_cb->event) {
369 case UDI_CHANNEL_BOUND:
370 /* Allocate a bus bind control block. */
371 udi_cb_alloc(cmos_bind_to_parent_1,
372 UDI_GCB(channel_event_cb),
373 BUS_BIND_CB_IDX,
374 channel_event_cb->gcb.channel);
375 break;
376 case UDI_CONSTRAINTS_CHANGED:
377 /* TODO: Handle propagation */
378 default:
379 udi_channel_event_complete(channel_event_cb, UDI_OK);
380 }
381 }
382
383 static void
384 cmos_bind_to_parent_1(
385 udi_cb_t *gcb,
386 udi_cb_t *new_cb)
387 {
388 udi_bus_bind_cb_t *bus_bind_cb =
389 UDI_MCB(new_cb, udi_bus_bind_cb_t);
390
391 /* Keep a link back to the channel event CB for the ack. */
392 bus_bind_cb->gcb.initiator_context = gcb;
393
394 /* Bind to the parent bus bridge driver. */
395 udi_bus_bind_req(bus_bind_cb);
396 }
397
398 static void cmos_bus_bind_ack_1(udi_cb_t *, udi_pio_handle_t);
399
400 static void
401 cmos_bus_bind_ack(
402 udi_bus_bind_cb_t *bus_bind_cb,
403 udi_ubit8_t preferred_endianness,
404 udi_status_t status)
405 {
406 cmos_region_data_t *rdata = bus_bind_cb->gcb.context;
407
408 /*
409 * Don't need to do anything with preferred_endianness, since
410 * our device doesn't do DMA. Even if it did,
411 * preferred_endianness is only used with bi-endianness devices
412 * that can change endianness.
413 */
414
415 /*
416 * Save the bus bind control block for unbinding later.
417 */
418 rdata->bus_bind_cb = bus_bind_cb;
419
420 /*
421 * Now we have access to our hardware. Set up the PIO mappings
422 * we'll need later.
423 */
424 udi_pio_map(cmos_bus_bind_ack_1, UDI_GCB(bus_bind_cb),
425 CMOS_REGSET, CMOS_BASE, CMOS_LENGTH,
426 cmos_trans_read,
427 sizeof cmos_trans_read / sizeof(udi_pio_trans_t),
428 UDI_PIO_STRICTORDER, CMOS_PACE);
429 }
430
431 static void cmos_bus_bind_ack_2(udi_cb_t *, udi_pio_handle_t);
432
433 static void
434 cmos_bus_bind_ack_1(
435 udi_cb_t *gcb,
436 udi_pio_handle_t new_pio_handle)
437 {
438 cmos_region_data_t *rdata = gcb->context;
439
440 /* Save the PIO handle for later use. */
441 rdata->trans_read = new_pio_handle;
442
443 udi_pio_map(cmos_bus_bind_ack_2, gcb,
444 CMOS_REGSET, CMOS_BASE, CMOS_LENGTH,
445 cmos_trans_write,
446 sizeof cmos_trans_write / sizeof(udi_pio_trans_t),
447 UDI_PIO_STRICTORDER, CMOS_PACE);
448 }
449
450 static void
451 cmos_bus_bind_ack_2(
452 udi_cb_t *gcb,
453 udi_pio_handle_t new_pio_handle)
454 {
455 cmos_region_data_t *rdata = gcb->context;
456 udi_channel_event_cb_t *channel_event_cb =
457 gcb->initiator_context;
458
459 /* Save the PIO handle for later use. */
460 rdata->trans_write = new_pio_handle;
461
462 #if DO_INTERRUPTS
463 /* Attach interrupts here... */
464 #endif
465
466 /* Let the MA know we've completed binding. */
467 udi_channel_event_complete(channel_event_cb, UDI_OK);
468 }
469
470 static void
471 cmos_gio_bind_req(udi_gio_bind_cb_t *gio_bind_cb)
472 {
473 udi_gio_bind_ack(gio_bind_cb, CMOS_DEVSIZE, 0, UDI_OK);
474 }
475
476 static void
477 cmos_gio_unbind_req(udi_gio_bind_cb_t *gio_bind_cb)
478 {
479 udi_gio_unbind_ack(gio_bind_cb);
480 }
481
482 static void
483 cmos_child_channel_event(udi_channel_event_cb_t *channel_event_cb)
484 {
485 udi_channel_event_complete(channel_event_cb, UDI_OK);
486 }
487
488 static void cmos_do_read(udi_gio_xfer_cb_t *, udi_ubit8_t);
489 static void cmos_do_write(udi_gio_xfer_cb_t *, udi_ubit8_t);
490
491 static void
492 cmos_gio_xfer_req(udi_gio_xfer_cb_t *gio_xfer_cb)
493 {
494 udi_gio_rw_params_t *rw_params = gio_xfer_cb->tr_params;
495
496 /*
497 * We can ignore the timeout parameter since all of our
498 * operations are synchronous.
499 */
500
501 switch (gio_xfer_cb->op) {
502 case UDI_GIO_OP_READ:
503 udi_assert(rw_params->offset_hi == 0 &&
504 rw_params->offset_lo < CMOS_DEVSIZE &&
505 gio_xfer_cb->data_buf->buf_size <
506 CMOS_DEVSIZE - rw_params->offset_lo);
507 cmos_do_read(gio_xfer_cb, rw_params->offset_lo);
508 break;
509 case UDI_GIO_OP_WRITE:
510 udi_assert(rw_params->offset_hi == 0 &&
511 rw_params->offset_lo < CMOS_DEVSIZE &&
512 gio_xfer_cb->data_buf->buf_size <
513 CMOS_DEVSIZE - rw_params->offset_lo);
514 cmos_do_write(gio_xfer_cb, rw_params->offset_lo);
515 break;
516 default:
517 udi_gio_xfer_nak(gio_xfer_cb, UDI_STAT_NOT_UNDERSTOOD);
518 }
519 }
520
521 static void cmos_do_read_1(udi_cb_t *, udi_buf_t *,
522 udi_status_t, udi_ubit16_t);
523
524 static void
525 cmos_do_read(udi_gio_xfer_cb_t *gio_xfer_cb, udi_ubit8_t addr)
526 {
527 cmos_region_data_t *rdata = gio_xfer_cb->gcb.context;
528 cmos_gio_xfer_scratch_t *gio_xfer_scratch =
529 gio_xfer_cb->gcb.scratch;
530
531 /*
532 * Store address into first byte of scratch space,
533 * so the trans list can get at it.
534 */
535 gio_xfer_scratch->addr = addr;
536 gio_xfer_scratch->count = gio_xfer_cb->data_buf->buf_size;
537
538 udi_pio_trans(cmos_do_read_1, gcb,
539 rdata->trans_read,
540 new_buf, NULL);
541 }
542
543 static void
544 cmos_do_read_1(
545 udi_cb_t *gcb,
546 udi_buf_t *new_buf,
547 udi_status_t status,
548 udi_ubit16_t result)
549 {
550 udi_gio_xfer_cb_t *gio_xfer_cb =
551 UDI_MCB(gcb, udi_gio_xfer_cb_t);
552
553 /* udi_pio_trans may create a new buffer. */
554 gio_xfer_cb->data_buf = new_buf;
555
556 if (status == UDI_OK)
557 udi_gio_xfer_ack(gio_xfer_cb);
558 else
559 udi_gio_xfer_nak(gio_xfer_cb, status);
560 }
561
562 static void cmos_do_write_1(udi_cb_t *, udi_buf_t *,
563 udi_status_t, udi_ubit16_t);
564
565 static void
566 cmos_do_write(udi_gio_xfer_cb_t *gio_xfer_cb, udi_ubit8_t addr)
567 {
568 cmos_region_data_t *rdata = UDI_GCB(gio_xfer_cb)->context;
569 cmos_gio_xfer_scratch_t *gio_xfer_scratch =
570 gio_xfer_cb->gcb.scratch;
571
572 /*
573 * The first CMOS_RDONLY_SZ bytes of this device are not
574 * allowed to be written through this driver. Fail any attempt
575 * to write to these bytes.
576 */
577 if (addr < CMOS_RDONLY_SZ) {
578 udi_gio_xfer_nak(gio_xfer_cb,
579 UDI_STAT_MISTAKEN_IDENTITY);
580 return;
581 }
582
583 /*
584 * Store address into first byte of scratch space,
585 * so the trans list can get at it. The data to write
586 * will be accessed directly from the buffer.
587 */
588 gio_xfer_scratch->addr = addr;
589 gio_xfer_scratch->count = gio_xfer_cb->data_buf->buf_size;
590
591 udi_pio_trans(cmos_do_write_1, UDI_GCB(gio_xfer_cb),
592 rdata->trans_write,
593 gio_xfer_cb->data_buf, NULL);
594 }
595
596 static void
597 cmos_do_write_1(
598 udi_cb_t *gcb,
599 udi_buf_t *new_buf,
600 udi_status_t status,
601 udi_ubit16_t result)
602 {
603 udi_gio_xfer_cb_t *gio_xfer_cb =
604 UDI_MCB(gcb, udi_gio_xfer_cb_t);
605
606 /* udi_pio_trans may create a new buffer. */
607 gio_xfer_cb->data_buf = new_buf;
608
609 if (status == UDI_OK)
610 udi_gio_xfer_ack(gio_xfer_cb);
611 else
612 udi_gio_xfer_nak(gio_xfer_cb, status);
613 }
614
615 static void
616 cmos_devmgmt_req(
617 udi_mgmt_cb_t *cb,
618 udi_ubit8_t mgmt_op,
619 udi_ubit8_t parent_id)
620 {
621 cmos_region_data_t *rdata = cb->gcb.context;
622
623 switch (mgmt_op) {
624 case UDI_DMGMT_UNBIND:
625 #if DO_INTERRUPTS
626 /* Detach interrupts here... */
627 #endif
628 /* Keep a link back to this CB for use in the ack. */
629 rdata->bus_bind_cb->gcb.initiator_context = cb;
630
631 /* Do the metalanguage-specific unbind. */
632 udi_bus_unbind_req(rdata->bus_bind_cb);
633 default:
634 udi_devmgmt_ack(cb, 0, UDI_OK);
635 }
636 }
637
638 static void
639 cmos_bus_unbind_ack(udi_bus_bind_cb_t *bus_bind_cb)
640 {
641 udi_mgmt_cb_t *cb = bus_bind_cb->gcb.initiator_context;
642
643 udi_cb_free(UDI_GCB(bus_bind_cb));
644
645 udi_devmgmt_ack(cb, 0, UDI_OK);
646 }
647
648 static void
649 cmos_final_cleanup_req(udi_mgmt_cb_t *cb)
650 {
651 /*
652 * We have nothing to free that wasn't already freed by
653 * unbinding children and parents.
654 */
655 udi_final_cleanup_ack(cb);
656 }
657
658 #if DO_INTERRUPTS
659
660 static void
661 cmos_intr_attach_ack(
662 udi_intr_attach_cb_t *intr_attach_cb,
663 udi_status_t status)
664 {
665 /* Complete interrupt attachment here... */
666 }
667
668 static void
669 cmos_intr_detach_ack(
670 udi_intr_attach_cb_t *intr_attach_cb,
671 udi_status_t status)
672 {
673 /* Complete interrupt detachment here... */
674 }
675
676 static void
677 cmos_intr_event_ind(
678 udi_intr_event_cb_t *intr_event_cb,
679 udi_ubit8_t flags)
680 {
681 cmos_region_data_t *rdata = UDI_GCB(intr_event_cb)->context;
682
683 /* Handle interrupt... */
684
685 /* Acknowledge the interrupt */
686 udi_intr_event_res(intr_event_cb, UDI_INTR_ASSUMED, UDI_OK);
687 }
688
689 static void
690 cmos_intr_channel_event(udi_channel_event_cb_t *channel_event_cb)
691 {
692 udi_channel_event_complete(channel_event_cb, UDI_OK);
693 }
694
695 #endif /* DO_INTERRUPTS */
Sample driver source code provided by SCO.
This source code may be used and distributed freely, in whole or in part.