2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
23 #include <ipxe/interface.h>
31 /*****************************************************************************
38 * Close null interface
40 * @v intf Null interface
41 * @v rc Reason for close
43 static void null_intf_close ( struct interface *intf __unused,
46 /* Do nothing. In particular, do not call intf_restart(),
47 * since that would result in an infinite loop.
51 /** Null interface operations */
52 static struct interface_operation null_intf_op[] = {
53 INTF_OP ( intf_close, struct interface *, null_intf_close ),
56 /** Null interface descriptor */
57 struct interface_descriptor null_intf_desc =
58 INTF_DESC_PURE ( null_intf_op );
60 /** The null interface */
61 struct interface null_intf = INTF_INIT ( null_intf_desc );
63 /*****************************************************************************
65 * Object interface plumbing
70 * Plug an object interface into a new destination object interface
72 * @v intf Object interface
73 * @v dest New destination object interface
75 * The reference to the existing destination interface is dropped, a
76 * reference to the new destination interface is obtained, and the
77 * interface is updated to point to the new destination interface.
79 * Note that there is no "unplug" call; instead you must plug the
80 * interface into a null interface.
82 void intf_plug ( struct interface *intf, struct interface *dest ) {
83 DBGC ( INTF_COL ( intf ),
84 "INTF " INTF_INTF_FMT " replug to " INTF_FMT "\n",
85 INTF_INTF_DBG ( intf, intf->dest ), INTF_DBG ( dest ) );
87 intf_put ( intf->dest );
92 * Plug two object interfaces together
94 * @v a Object interface A
95 * @v b Object interface B
97 * Plugs interface A into interface B, and interface B into interface
98 * A. (The basic plug() function is unidirectional; this function is
99 * merely a shorthand for two calls to plug(), hence the name.)
101 void intf_plug_plug ( struct interface *a, struct interface *b ) {
107 * Unplug an object interface
109 * @v intf Object interface
111 void intf_unplug ( struct interface *intf ) {
112 intf_plug ( intf, &null_intf );
116 * Ignore all further operations on an object interface
118 * @v intf Object interface
120 void intf_nullify ( struct interface *intf ) {
121 intf->desc = &null_intf_desc;
125 * Increment reference count on an object interface
127 * @v intf Object interface
128 * @ret intf Object interface
130 struct interface * intf_get ( struct interface *intf ) {
131 ref_get ( intf->refcnt );
136 * Decrement reference count on an object interface
138 * @v intf Object interface
140 void intf_put ( struct interface *intf ) {
141 ref_put ( intf->refcnt );
145 * Get pointer to object containing object interface
147 * @v intf Object interface
148 * @ret object Containing object
150 void * intf_object ( struct interface *intf ) {
151 return ( ( ( void * ) intf ) - intf->desc->offset );
155 * Get pass-through interface
157 * @v intf Object interface
158 * @ret passthru Pass-through interface, or NULL
160 static struct interface * intf_get_passthru ( struct interface *intf ) {
161 struct interface_descriptor *desc = intf->desc;
163 if ( desc->passthru_offset ) {
164 return ( ( ( void * ) intf ) + desc->passthru_offset );
171 * Get object interface destination and operation method (without pass-through)
173 * @v intf Object interface
174 * @v type Operation type
175 * @ret dest Destination interface
176 * @ret func Implementing method, or NULL
178 void * intf_get_dest_op_no_passthru_untyped ( struct interface *intf,
180 struct interface **dest ) {
181 struct interface_descriptor *desc;
182 struct interface_operation *op;
185 *dest = intf_get ( intf->dest );
186 desc = (*dest)->desc;
187 for ( i = desc->num_op, op = desc->op ; i ; i--, op++ ) {
188 if ( op->type == type )
196 * Get object interface destination and operation method
198 * @v intf Object interface
199 * @v type Operation type
200 * @ret dest Destination interface
201 * @ret func Implementing method, or NULL
203 void * intf_get_dest_op_untyped ( struct interface *intf, void *type,
204 struct interface **dest ) {
209 /* Search for an implementing method provided by the
210 * current destination interface.
212 func = intf_get_dest_op_no_passthru_untyped( intf, type, dest );
216 /* Pass through to the underlying interface, if applicable */
217 if ( ! ( intf = intf_get_passthru ( *dest ) ) )
223 /*****************************************************************************
225 * Generic interface operations
230 * Close an object interface
232 * @v intf Object interface
233 * @v rc Reason for close
235 * Note that this function merely informs the destination object that
236 * the interface is about to be closed; it doesn't actually disconnect
237 * the interface. In most cases, you probably want to use
238 * intf_shutdown() or intf_restart() instead.
240 void intf_close ( struct interface *intf, int rc ) {
241 struct interface *dest;
242 intf_close_TYPE ( void * ) *op =
243 intf_get_dest_op ( intf, intf_close, &dest );
244 void *object = intf_object ( dest );
246 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " close (%s)\n",
247 INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
252 /* Default is to restart the interface */
253 intf_restart ( dest, rc );
260 * Shut down an object interface
262 * @v intf Object interface
263 * @v rc Reason for close
265 * Blocks further operations from being received via the interface,
266 * executes a close operation on the destination interface, and
267 * unplugs the interface.
269 void intf_shutdown ( struct interface *intf, int rc ) {
271 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n",
272 INTF_DBG ( intf ), strerror ( rc ) );
274 /* Block further operations */
275 intf_nullify ( intf );
277 /* Notify destination of close */
278 intf_close ( intf, rc );
280 /* Unplug interface */
281 intf_unplug ( intf );
285 * Shut down and restart an object interface
287 * @v intf Object interface
288 * @v rc Reason for close
290 * Shuts down the interface, then unblocks operations that were
291 * blocked during shutdown.
293 void intf_restart ( struct interface *intf, int rc ) {
294 struct interface_descriptor *desc = intf->desc;
296 /* Shut down the interface */
297 intf_shutdown ( intf, rc );
299 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " restarting\n",
302 /* Restore the interface descriptor. Must be done after
303 * shutdown (rather than inhibiting intf_shutdown() from
304 * nullifying the descriptor) in order to avoid a potential
305 * infinite loop as the intf_close() operations on each side
306 * of the link call each other recursively.