iPXE
interface.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <ipxe/interface.h>
00028 
00029 /** @file
00030  *
00031  * Object interfaces
00032  *
00033  */
00034 
00035 /*****************************************************************************
00036  *
00037  * The null interface
00038  *
00039  */
00040 
00041 /**
00042  * Close null interface
00043  *
00044  * @v intf              Null interface
00045  * @v rc                Reason for close
00046  */
00047 static void null_intf_close ( struct interface *intf __unused,
00048                               int rc __unused ) {
00049 
00050         /* Do nothing.  In particular, do not call intf_restart(),
00051          * since that would result in an infinite loop.
00052          */
00053 }
00054 
00055 /** Null interface operations */
00056 static struct interface_operation null_intf_op[] = {
00057         INTF_OP ( intf_close, struct interface *, null_intf_close ),
00058 };
00059 
00060 /** Null interface descriptor */
00061 struct interface_descriptor null_intf_desc =
00062         INTF_DESC_PURE ( null_intf_op );
00063 
00064 /** The null interface */
00065 struct interface null_intf = INTF_INIT ( null_intf_desc );
00066 
00067 /*****************************************************************************
00068  *
00069  * Object interface plumbing
00070  *
00071  */
00072 
00073 /**
00074  * Plug an object interface into a new destination object interface
00075  *
00076  * @v intf              Object interface
00077  * @v dest              New destination object interface
00078  *
00079  * The reference to the existing destination interface is dropped, a
00080  * reference to the new destination interface is obtained, and the
00081  * interface is updated to point to the new destination interface.
00082  */
00083 void intf_plug ( struct interface *intf, struct interface *dest ) {
00084         DBGC ( INTF_COL ( intf ),
00085                "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n",
00086                INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) );
00087         intf_get ( dest );
00088         intf_put ( intf->dest );
00089         intf->dest = dest;
00090 }
00091 
00092 /**
00093  * Plug two object interfaces together
00094  *
00095  * @v a                 Object interface A
00096  * @v b                 Object interface B
00097  *
00098  * Plugs interface A into interface B, and interface B into interface
00099  * A.  (The basic plug() function is unidirectional; this function is
00100  * merely a shorthand for two calls to plug(), hence the name.)
00101  */
00102 void intf_plug_plug ( struct interface *a, struct interface *b ) {
00103         intf_plug ( a, b );
00104         intf_plug ( b, a );
00105 }
00106 
00107 /**
00108  * Unplug an object interface
00109  *
00110  * @v intf              Object interface
00111  */
00112 void intf_unplug ( struct interface *intf ) {
00113         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " unplug\n",
00114                INTF_INTF_DBG ( intf, intf->dest ) );
00115         intf_put ( intf->dest );
00116         intf->dest = &null_intf;
00117 }
00118 
00119 /**
00120  * Ignore all further operations on an object interface
00121  *
00122  * @v intf              Object interface
00123  */
00124 void intf_nullify ( struct interface *intf ) {
00125         intf->desc = &null_intf_desc;
00126 }
00127 
00128 /**
00129  * Increment reference count on an object interface
00130  *
00131  * @v intf              Object interface
00132  * @ret intf            Object interface
00133  */
00134 struct interface * intf_get ( struct interface *intf ) {
00135         ref_get ( intf->refcnt );
00136         return intf;
00137 }
00138 
00139 /**
00140  * Decrement reference count on an object interface
00141  *
00142  * @v intf              Object interface
00143  */
00144 void intf_put ( struct interface *intf ) {
00145         ref_put ( intf->refcnt );
00146 }
00147 
00148 /**
00149  * Get pointer to object containing object interface
00150  *
00151  * @v intf              Object interface
00152  * @ret object          Containing object
00153  */
00154 void * intf_object ( struct interface *intf ) {
00155         return ( ( ( void * ) intf ) - intf->desc->offset );
00156 }
00157 
00158 /**
00159  * Get pass-through interface
00160  *
00161  * @v intf              Object interface
00162  * @ret passthru        Pass-through interface, or NULL
00163  */
00164 static struct interface * intf_get_passthru ( struct interface *intf ) {
00165         struct interface_descriptor *desc = intf->desc;
00166 
00167         if ( desc->passthru_offset ) {
00168                 return ( ( ( void * ) intf ) + desc->passthru_offset );
00169         } else {
00170                 return NULL;
00171         }
00172 }
00173 
00174 /**
00175  * Get object interface destination and operation method (without pass-through)
00176  *
00177  * @v intf              Object interface
00178  * @v type              Operation type
00179  * @ret dest            Destination interface
00180  * @ret func            Implementing method, or NULL
00181  */
00182 void * intf_get_dest_op_no_passthru_untyped ( struct interface *intf,
00183                                               void *type,
00184                                               struct interface **dest ) {
00185         struct interface_descriptor *desc;
00186         struct interface_operation *op;
00187         unsigned int i;
00188 
00189         *dest = intf_get ( intf->dest );
00190         desc = (*dest)->desc;
00191         for ( i = desc->num_op, op = desc->op ; i ; i--, op++ ) {
00192                 if ( op->type == type )
00193                         return op->func;
00194         }
00195 
00196         return NULL;
00197 }
00198 
00199 /**
00200  * Get object interface destination and operation method
00201  *
00202  * @v intf              Object interface
00203  * @v type              Operation type
00204  * @ret dest            Destination interface
00205  * @ret func            Implementing method, or NULL
00206  */
00207 void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
00208                                   struct interface **dest ) {
00209         void *func;
00210 
00211         while ( 1 ) {
00212 
00213                 /* Search for an implementing method provided by the
00214                  * current destination interface.
00215                  */
00216                 func = intf_get_dest_op_no_passthru_untyped( intf, type, dest );
00217                 if ( func )
00218                         return func;
00219 
00220                 /* Pass through to the underlying interface, if applicable */
00221                 if ( ! ( intf = intf_get_passthru ( *dest ) ) )
00222                         return NULL;
00223                 intf_put ( *dest );
00224         }
00225 }
00226 
00227 /*****************************************************************************
00228  *
00229  * Generic interface operations
00230  *
00231  */
00232 
00233 /**
00234  * Close an object interface
00235  *
00236  * @v intf              Object interface
00237  * @v rc                Reason for close
00238  *
00239  * Note that this function merely informs the destination object that
00240  * the interface is about to be closed; it doesn't actually disconnect
00241  * the interface.  In most cases, you probably want to use
00242  * intf_shutdown() or intf_restart() instead.
00243  */
00244 void intf_close ( struct interface *intf, int rc ) {
00245         struct interface *dest;
00246         intf_close_TYPE ( void * ) *op =
00247                 intf_get_dest_op ( intf, intf_close, &dest );
00248         void *object = intf_object ( dest );
00249 
00250         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " close (%s)\n",
00251                INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
00252 
00253         if ( op ) {
00254                 op ( object, rc );
00255         } else {
00256                 /* Default is to restart the interface */
00257                 intf_restart ( dest, rc );
00258         }
00259 
00260         intf_put ( dest );
00261 }
00262 
00263 /**
00264  * Shut down an object interface
00265  *
00266  * @v intf              Object interface
00267  * @v rc                Reason for close
00268  *
00269  * Blocks further operations from being received via the interface,
00270  * executes a close operation on the destination interface, and
00271  * unplugs the interface.
00272  */
00273 void intf_shutdown ( struct interface *intf, int rc ) {
00274         struct interface tmp;
00275 
00276         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n",
00277                INTF_DBG ( intf ), strerror ( rc ) );
00278 
00279         /* Block further operations */
00280         intf_nullify ( intf );
00281 
00282         /* Transfer destination to temporary interface */
00283         tmp.dest = intf->dest;
00284         intf->dest = &null_intf;
00285 
00286         /* Notify destination of close via temporary interface */
00287         intf_close ( &tmp, rc );
00288 
00289         /* Unplug temporary interface */
00290         intf_unplug ( &tmp );
00291 }
00292 
00293 /**
00294  * Shut down multiple object interfaces
00295  *
00296  * @v intfs             Object interfaces
00297  * @v rc                Reason for close
00298  */
00299 void intfs_vshutdown ( va_list intfs, int rc ) {
00300         struct interface *intf;
00301         va_list tmp;
00302 
00303         /* Nullify all interfaces to avoid potential loops */
00304         va_copy ( tmp, intfs );
00305         while ( ( intf = va_arg ( tmp, struct interface * ) ) )
00306                 intf_nullify ( intf );
00307         va_end ( tmp );
00308 
00309         /* Shut down all interfaces */
00310         while ( ( intf = va_arg ( intfs, struct interface * ) ) )
00311                 intf_shutdown ( intf, rc );
00312 }
00313 
00314 /**
00315  * Shut down multiple object interfaces
00316  *
00317  * @v rc                Reason for close
00318  * @v ...               Object interfaces
00319  */
00320 void intfs_shutdown ( int rc, ... ) {
00321         va_list intfs;
00322 
00323         va_start ( intfs, rc );
00324         intfs_vshutdown ( intfs, rc );
00325         va_end ( intfs );
00326 }
00327 
00328 /**
00329  * Shut down and restart an object interface
00330  *
00331  * @v intf              Object interface
00332  * @v rc                Reason for close
00333  *
00334  * Shuts down the interface, then unblocks operations that were
00335  * blocked during shutdown.
00336  */
00337 void intf_restart ( struct interface *intf, int rc ) {
00338 
00339         /* Shut down the interface */
00340         intf_shutdown ( intf, rc );
00341 
00342         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " restarting\n",
00343                INTF_DBG ( intf ) );
00344 
00345         /* Restore the interface descriptor.  Must be done after
00346          * shutdown (rather than inhibiting intf_shutdown() from
00347          * nullifying the descriptor) in order to avoid a potential
00348          * infinite loop as the intf_close() operations on each side
00349          * of the link call each other recursively.
00350          */
00351         intf_reinit ( intf );
00352 }
00353 
00354 /**
00355  * Shut down and restart multiple object interfaces
00356  *
00357  * @v intfs             Object interfaces
00358  * @v rc                Reason for close
00359  */
00360 void intfs_vrestart ( va_list intfs, int rc ) {
00361         struct interface *intf;
00362         va_list tmp;
00363 
00364         /* Shut down all interfaces */
00365         va_copy ( tmp, intfs );
00366         intfs_vshutdown ( tmp, rc );
00367         va_end ( tmp );
00368 
00369         /* Reinitialise all interfaces */
00370         while ( ( intf = va_arg ( intfs, struct interface * ) ) )
00371                 intf_reinit ( intf );
00372 }
00373 
00374 /**
00375  * Shut down and restart multiple object interfaces
00376  *
00377  * @v rc                Reason for close
00378  * @v ...               Object interfaces
00379  */
00380 void intfs_restart ( int rc, ... ) {
00381         va_list intfs;
00382 
00383         va_start ( intfs, rc );
00384         intfs_vrestart ( intfs, rc );
00385         va_end ( intfs );
00386 }
00387 
00388 /**
00389  * Poke an object interface
00390  *
00391  * @v intf              Object interface
00392  * @v type              Operation type
00393  *
00394  * This is a helper function to implement methods which take no
00395  * parameters and return nothing.
00396  */
00397 void intf_poke ( struct interface *intf,
00398                  void ( type ) ( struct interface *intf ) ) {
00399         struct interface *dest;
00400         intf_poke_TYPE ( void * ) *op =
00401                 intf_get_dest_op_untyped ( intf, type, &dest );
00402         void *object = intf_object ( dest );
00403 
00404         if ( op ) {
00405                 op ( object );
00406         } else {
00407                 /* Default is to do nothing */
00408         }
00409 
00410         intf_put ( dest );
00411 }