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.