[ Previous |
Next |
Contents |
Home |
Search ]
AIX Version 4.3 Understanding the Diagnostic Subsystem for AIX
Example TU open/close device interface
/*
* COMPONENT_NAME: (TU_DEVICE) Resource Interface Access Code
*
* FUNCTIONS: Do_INIT_TUS
* Do_TERM_TUS
*/
/* FILE NAME: device_interface.c */
/* FUNCTION: Device Adapter Application Interface Code */
/* */
/* This source file contains source code for the Device adapter's */
/* Application Test Units to aid in various testing environments */
/* of the device adapter. These test units provide a basic inter- */
/* face between the diagnostic application program and functions */
/* written in the diagnostic extension (pdiagex) which provide direct */
/* access to the device without the need for a device driver. */
/* */
/* */
/* INCLUDED FILES */
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <sys/intr.h>
#include <sys/dma.h>
#include "device_err_detail.h"
#include "tu.h"
#include <diag/tucb.h>
#include <sys/pdiagex_dds.h>
/*****************************************/
/*- INITIALIZE Test Unit #1 -*/
/*****************************************/
void
Do_INIT_TUS(TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data, TU_RETURN_TYPE *tu_rc)
{
int rc;
void *ih_handle;
/* Set initial tu success status */
tu_rc->major_rc = TU_SUCCESS;
/*- unconfigure device/children and place device in diagnose state -*/
rc = pdiag_diagnose_state(dev_tucb->resource_name);
if (rc != 0) { /*- test unit failed to complete normally -*/
tu_rc->major_rc = TU_DEVICE_BUSY;
tu_rc->minor_rc = rc;
return;
}
tu_data->adapter_diagnose_state = 1;
/* Get all the device attributes for the dds structure */
rc = get_dds( dev_tucb, tu_data );
if (rc != 0) { /*- test unit failed to complete normally -*/
tu_rc->major_rc = TU_SOFTWARE_ERROR;
tu_rc->minor_rc = rc;
return;
}
/************************************************************
* Call pdiag_open
* This also loads the interrupt handler
************************************************************/
/* Open the device for testing via PDIAGEX */
rc = pdiag_open( dev_tucb->resource_name, &tu_data->dds, "device_intr",
&tu_data->pdiagex_handle);
if (rc != 0) { /*- test unit failed to complete normally -*/
if ( dev_tucb->parms.msg_file != (FILE *)NULL)
fprintf( dev_tucb->parms.msg_file,
"pdiagex open rc = %d\n", rc);
tu_rc->major_rc = TU_DEVICE_BUSY;
tu_rc->minor_rc = rc;
return;
}
return; /*- normal completion -*/
}
/*****************************************/
/*- TERMINATE Test Unit #EFFF -*/
/*****************************************/
void
Do_TERM_TUS(TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data, TU_RETURN_TYPE *tu_rc)
{
int rc;
tu_rc->major_rc = TU_SUCCESS;
/* Close/terminate device from PDIAGEX */
/* This also unloads the interrupt handler */
rc = pdiag_close(tu_data->pdiagex_handle);
if ( rc != 0 ) {
if ( dev_tucb->parms.msg_file != (FILE *)NULL)
fprintf( dev_tucb->parms.msg_file,
"pdiagex close rc = %d\n", rc);
tu_rc->major_rc = TU_SOFTWARE_ERROR;
tu_rc->minor_rc = rc;
}
/*- reconfigure device/children to their original state -*/
rc = pdiag_restore_state(dev_tucb->resource_name);
if (rc != 0) { /*- test unit failed to complete normally -*/
tu_rc->major_rc = TU_SOFTWARE_ERROR;
tu_rc->minor_rc = rc;
}
return; /*- normal completion -*/
}
/*****************************************/
/*- Get the device attributes -*/
/*****************************************/
int
get_dds( TU_TYPE *dev_tucb, TU_GLOBAL_DATA *tu_data )
{
int rc;
char type;
char *parent_name;
/* Open/Initialize Configuration Services */
if ((rc = pdiag_cs_open()) != 0 )
return (rc);
/********************************************************/
/* Initialize the DDS structure with all pertinent data */
/********************************************************/
/* Get the parent name */
rc = pdiag_cs_get_attr(dev_tucb->resource_name, "parent_name", &parent_name, &type );
/* Bus ID for the parent resource */
rc = getatt(&tu_data->dds.bus_id,'l',parent_name,"bus_id",NULL);
pdiag_cs_free_attr ( parent_name );
/* Slot number */
rc=getatt(&tu_data->dds.slot_num,'i',dev_tucb->resource_name,
"connwhere", NULL);
/* Bus Interrupt Level */
rc=getatt(&tu_data->dds.bus_intr_lvl,'i',dev_tucb->resource_name,
"busintr", NULL);
/* assign bus_io_addr */
rc=getatt(&tu_data->dds.bus_io_addr,'l',dev_tucb->resource_name,
"busio",NULL);
/* assign bus_io_length */
rc=getatt(&tu_data->dds.bus_io_length,'l',dev_tucb->resource_name,
"bus_io_length",NULL);
/* assign bus_mem_addr */
rc=getatt(&tu_data->dds.bus_mem_addr,'l',dev_tucb->resource_name,
"bus_mem_addr",NULL);
/* assign bus_mem_length */
rc=getatt(&tu_data->dds.bus_mem_length,'l',dev_tucb->resource_name,
"bus_mem_length",NULL);
tu_data->dds.intr_priority = INTCLASS2;
tu_data->dds.intr_flags = NULL; /* not used by PCI */
tu_data->dds.dma_lvl = NULL; /* not used by PCI */
tu_data->dds.dma_bus_mem = NULL;
tu_data->dds.dma_bus_length = NULL;
tu_data->dds.dma_flags = DMA_MASTER;
tu_data->dds.bus_type = BUS_BID;
tu_data->dds.data_ptr = (uchar *)NULL;
tu_data->dds.maxmaster = 32;
/* Close Configuration Services */
pdiag_cs_close();
return (rc);
}
/**************************************************************************
* NAME: getatt
*
* FUNCTION: Obtains attribute from the configuration services
* database, or change list.
*
* EXECUTION ENVIRONMENT:
*
* NOTES:
*
* int
* getatt(dest_addr,dest_type,lname,att_name,newatt )
*
* dest_addr = pointer to the destination field.
* dest_type = The data type which the attribute is to be converted to
* 's' = string rep=s
* 'b' = byte sequence rep=s, e.g. "0x56FFE67.."
* 'l' = long rep=n
* 'i' = int rep=n
* 'h' = short (half) rep=n
* 'c' = char rep=n,or s
* 'a' = address rep=n
* lname = Device logical name. ( or parent's logical name )
* att_name = attribute name to retrieve
* newatt = New attributes to be scanned before reading database
*
*
* RETURNS:
* 0 = Successful
* <0 = Successful (for byte sequence only, = -ve no. of bytes)
* >0 = errno ( E_NOATTR = attribute not found )
*
**************************************************************************/
int getatt(dest_addr, dest_type, lname, att_name, newatt)
void *dest_addr; /* Address of destination */
char dest_type; /* Destination type */
char *lname; /* device logical name */
char *att_name; /* attribute name */
struct attr *newatt; /* List of new attributes */
{
struct attr *att_changed();
struct attr *att_ptr;
int convert_seq();
int rc;
char *val_ptr;
char rep;
char *value;
/* Note: We need an entry from customized, or predefined even if */
/* an entry from newatt is going to be used because there is no */
/* representation (rep) in newatt */
/* SEARCH FOR ENTRY */
rc = pdiag_cs_get_attr(lname, att_name, &value, &rep );
/* CONVERT THE DATA TYPE TO THE DESTINATION TYPE */
rc = convert_att(dest_addr, dest_type, value, rep );
/* Free up what the pdiag_cs_get_addr allocated */
pdiag_cs_free_attr( &value );
return(rc);
}
/*************************************************************************
* NAME: convert_att
*
* FUNCTION: This routine converts attributes into different data types
*
* EXECUTION ENVIRONMENT:
*
* Generally this routine is called by getatt(), but it is available
* to other procedures which need to convert data which may not also
* be represented in the database.
* No global variable are used, so this may be dynamically linked.
*
* RETURNS:
*
* 0 = Successful
* <0 = Successful (for byte sequence only, = -ve no. of bytes)
* >0 = errno
**************************************************************************/
int convert_att(dest_addr, dest_type, val_ptr, rep )
void *dest_addr; /* Address of destination */
char dest_type; /* Destination type */
char *val_ptr; /* Address of source */
char rep; /* Representation of source ('s', or 'n') */
{
if( rep == 's' ) {
switch( dest_type ) {
case 's':
strcpy( (char *)dest_addr, val_ptr );
break;
case 'c':
*(char *)dest_addr = *val_ptr;
break;
case 'b':
return ( convert_seq( val_ptr, (char *)dest_addr ) );
case 'i':
*(int *)dest_addr =
(int)strtoul( val_ptr, (char **)NULL, 0);
break;
default:
return 1;
}
} else if( rep == 'n' ) {
switch( dest_type ) {
case 'l':
*(long *)dest_addr =
strtoul( val_ptr, (char **)NULL, 0);
break;
case 'i':
*(int *)dest_addr =
(int)strtoul( val_ptr, (char **)NULL, 0);
break;
case 'h':
*(short *)dest_addr =
(short)strtoul( val_ptr, (char **)NULL, 0);
break;
case 'c':
*(char *)dest_addr =
(char)strtoul( val_ptr, (char **)NULL, 0);
break;
case 'a':
*(void **)dest_addr =
(void *)strtoul( val_ptr, (char **)NULL, 0);
break;
default:
return 1;
}
} else {
return 1;
}
return 0;
}
/**************************************************************************
* NAME: convert_seq
*
* FUNCTION: Converts a hex-style string to a sequence of bytes
*
* EXECUTION ENVIRONMENT:
*
* This routine uses no global variables
*
* NOTES:
*
* The string to be converted is of the form
* "0xFFAAEE5A567456724650789789ABDEF678" (for example)
* This would put the code FF into the first byte, AA into the second,
* etc.
*
* RETURNS: No of bytes, or -3 if error.
*
***************************************************************************/
int convert_seq( source, dest )
char *source;
uchar *dest;
{
char byte_val[5]; /* e.g. "0x5F\0" */
int byte_count = 0;
uchar tmp_val;
char *end_ptr;
strcpy( byte_val, "0x00" );
if( *source == '\0' ) { /* Accept empty string as legal */
return 0;
}
if( *source++ != '0' ) {
return 1;
}
if( tolower(*source++) != 'x' ) {
return 1;
}
while( ( byte_val[2] = *source ) && ( byte_val[3] = *(source+1) ) ) {
source += 2;
/* be careful not to store illegal bytes in case the
* destination is of exact size, and the source has
* trailing blanks
*/
tmp_val = (uchar) strtoul( byte_val, &end_ptr, 0 );
if( end_ptr != &byte_val[4] ) {
break;
}
*dest++ = tmp_val;
byte_count++;
}
return -byte_count;
}
[ Previous |
Next |
Contents |
Home |
Search ]