blob: a582bf2d79872f2c796cd4c6ae9ba7d4169db721 [file] [log] [blame]
wdenk5d3207d2002-08-21 22:08:56 +00001/*
2 * (C) Copyright 2002
3 * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
4 * Keith Outwater, keith_outwater@mvis.com
5 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
wdenk5d3207d2002-08-21 22:08:56 +00007 */
8
9/*
10 * Configuration support for Xilinx Virtex2 devices. Based
11 * on spartan2.c (Rich Ireland, rireland@enterasys.com).
12 */
13
14#include <common.h>
15#include <virtex2.h>
16
Wolfgang Denk9a9200b2005-09-24 23:41:00 +020017#if 0
18#define FPGA_DEBUG
Wolfgang Denk265817c2005-09-25 00:53:22 +020019#endif
Wolfgang Denk9a9200b2005-09-24 23:41:00 +020020
wdenk5d3207d2002-08-21 22:08:56 +000021#ifdef FPGA_DEBUG
22#define PRINTF(fmt,args...) printf (fmt ,##args)
23#else
24#define PRINTF(fmt,args...)
25#endif
26
27/*
28 * If the SelectMap interface can be overrun by the processor, define
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020029 * CONFIG_SYS_FPGA_CHECK_BUSY and/or CONFIG_FPGA_DELAY in the board configuration
wdenk5d3207d2002-08-21 22:08:56 +000030 * file and add board-specific support for checking BUSY status. By default,
31 * assume that the SelectMap interface cannot be overrun.
32 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020033#ifndef CONFIG_SYS_FPGA_CHECK_BUSY
34#undef CONFIG_SYS_FPGA_CHECK_BUSY
wdenk5d3207d2002-08-21 22:08:56 +000035#endif
36
37#ifndef CONFIG_FPGA_DELAY
38#define CONFIG_FPGA_DELAY()
39#endif
40
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020041#ifndef CONFIG_SYS_FPGA_PROG_FEEDBACK
42#define CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +000043#endif
44
45/*
46 * Don't allow config cycle to be interrupted
47 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020048#ifndef CONFIG_SYS_FPGA_CHECK_CTRLC
49#undef CONFIG_SYS_FPGA_CHECK_CTRLC
wdenk5d3207d2002-08-21 22:08:56 +000050#endif
51
52/*
53 * Check for errors during configuration by default
54 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020055#ifndef CONFIG_SYS_FPGA_CHECK_ERROR
56#define CONFIG_SYS_FPGA_CHECK_ERROR
wdenk5d3207d2002-08-21 22:08:56 +000057#endif
58
59/*
60 * The default timeout in mS for INIT_B to deassert after PROG_B has
61 * been deasserted. Per the latest Virtex II Handbook (page 347), the
62 * max time from PORG_B deassertion to INIT_B deassertion is 4uS per
63 * data frame for the XC2V8000. The XC2V8000 has 2860 data frames
64 * which yields 11.44 mS. So let's make it bigger in order to handle
65 * an XC2V1000, if anyone can ever get ahold of one.
66 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020067#ifndef CONFIG_SYS_FPGA_WAIT_INIT
68#define CONFIG_SYS_FPGA_WAIT_INIT CONFIG_SYS_HZ/2 /* 500 ms */
wdenk5d3207d2002-08-21 22:08:56 +000069#endif
70
71/*
72 * The default timeout for waiting for BUSY to deassert during configuration.
73 * This is normally not necessary since for most reasonable configuration
74 * clock frequencies (i.e. 66 MHz or less), BUSY monitoring is unnecessary.
75 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020076#ifndef CONFIG_SYS_FPGA_WAIT_BUSY
77#define CONFIG_SYS_FPGA_WAIT_BUSY CONFIG_SYS_HZ/200 /* 5 ms*/
wdenk5d3207d2002-08-21 22:08:56 +000078#endif
79
80/* Default timeout for waiting for FPGA to enter operational mode after
81 * configuration data has been written.
82 */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020083#ifndef CONFIG_SYS_FPGA_WAIT_CONFIG
84#define CONFIG_SYS_FPGA_WAIT_CONFIG CONFIG_SYS_HZ/5 /* 200 ms */
wdenk5d3207d2002-08-21 22:08:56 +000085#endif
86
Michal Simekf8c1be92014-03-13 12:49:21 +010087static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize);
88static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize);
wdenk5d3207d2002-08-21 22:08:56 +000089
Michal Simekf8c1be92014-03-13 12:49:21 +010090static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize);
91static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize);
wdenk5d3207d2002-08-21 22:08:56 +000092
Michal Simekf8c1be92014-03-13 12:49:21 +010093int virtex2_load(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +000094{
95 int ret_val = FPGA_FAIL;
96
97 switch (desc->iface) {
98 case slave_serial:
99 PRINTF ("%s: Launching Slave Serial Load\n", __FUNCTION__);
Michal Simekd9071ce2014-03-13 11:33:36 +0100100 ret_val = virtex2_ss_load(desc, buf, bsize);
wdenk5d3207d2002-08-21 22:08:56 +0000101 break;
102
103 case slave_selectmap:
104 PRINTF ("%s: Launching Slave Parallel Load\n", __FUNCTION__);
Michal Simekd9071ce2014-03-13 11:33:36 +0100105 ret_val = virtex2_ssm_load(desc, buf, bsize);
wdenk5d3207d2002-08-21 22:08:56 +0000106 break;
107
108 default:
109 printf ("%s: Unsupported interface type, %d\n",
110 __FUNCTION__, desc->iface);
111 }
112 return ret_val;
113}
114
Michal Simekf8c1be92014-03-13 12:49:21 +0100115int virtex2_dump(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +0000116{
117 int ret_val = FPGA_FAIL;
118
119 switch (desc->iface) {
120 case slave_serial:
121 PRINTF ("%s: Launching Slave Serial Dump\n", __FUNCTION__);
Michal Simekd9071ce2014-03-13 11:33:36 +0100122 ret_val = virtex2_ss_dump(desc, buf, bsize);
wdenk5d3207d2002-08-21 22:08:56 +0000123 break;
124
125 case slave_parallel:
126 PRINTF ("%s: Launching Slave Parallel Dump\n", __FUNCTION__);
Michal Simekd9071ce2014-03-13 11:33:36 +0100127 ret_val = virtex2_ssm_dump(desc, buf, bsize);
wdenk5d3207d2002-08-21 22:08:56 +0000128 break;
129
130 default:
131 printf ("%s: Unsupported interface type, %d\n",
132 __FUNCTION__, desc->iface);
133 }
134 return ret_val;
135}
136
Michal Simekf8c1be92014-03-13 12:49:21 +0100137int virtex2_info(xilinx_desc *desc)
wdenk5d3207d2002-08-21 22:08:56 +0000138{
139 return FPGA_SUCCESS;
140}
141
wdenk5d3207d2002-08-21 22:08:56 +0000142/*
143 * Virtex-II Slave SelectMap configuration loader. Configuration via
144 * SelectMap is as follows:
145 * 1. Set the FPGA's PROG_B line low.
146 * 2. Set the FPGA's PROG_B line high. Wait for INIT_B to go high.
147 * 3. Write data to the SelectMap port. If INIT_B goes low at any time
148 * this process, a configuration error (most likely CRC failure) has
149 * ocurred. At this point a status word may be read from the
150 * SelectMap interface to determine the source of the problem (You
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200151 * could, for instance, put this in your 'abort' function handler).
wdenk5d3207d2002-08-21 22:08:56 +0000152 * 4. After all data has been written, test the state of the FPGA
153 * INIT_B and DONE lines. If both are high, configuration has
154 * succeeded. Congratulations!
155 */
Michal Simekf8c1be92014-03-13 12:49:21 +0100156static int virtex2_ssm_load(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +0000157{
158 int ret_val = FPGA_FAIL;
Michal Simekd9071ce2014-03-13 11:33:36 +0100159 xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns;
wdenk5d3207d2002-08-21 22:08:56 +0000160
161 PRINTF ("%s:%d: Start with interface functions @ 0x%p\n",
162 __FUNCTION__, __LINE__, fn);
163
164 if (fn) {
165 size_t bytecount = 0;
166 unsigned char *data = (unsigned char *) buf;
167 int cookie = desc->cookie;
168 unsigned long ts;
169
170 /* Gotta split this one up (so the stack won't blow??) */
171 PRINTF ("%s:%d: Function Table:\n"
172 " base 0x%p\n"
173 " struct 0x%p\n"
174 " pre 0x%p\n"
175 " prog 0x%p\n"
176 " init 0x%p\n"
177 " error 0x%p\n",
178 __FUNCTION__, __LINE__,
179 &fn, fn, fn->pre, fn->pgm, fn->init, fn->err);
180 PRINTF (" clock 0x%p\n"
181 " cs 0x%p\n"
182 " write 0x%p\n"
183 " rdata 0x%p\n"
184 " wdata 0x%p\n"
185 " busy 0x%p\n"
186 " abort 0x%p\n"
187 " post 0x%p\n\n",
188 fn->clk, fn->cs, fn->wr, fn->rdata, fn->wdata,
189 fn->busy, fn->abort, fn->post);
190
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200191#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000192 printf ("Initializing FPGA Device %d...\n", cookie);
193#endif
194 /*
195 * Run the pre configuration function if there is one.
196 */
197 if (*fn->pre) {
198 (*fn->pre) (cookie);
199 }
200
201 /*
202 * Assert the program line. The minimum pulse width for
203 * Virtex II devices is 300 nS (Tprogram parameter in datasheet).
204 * There is no maximum value for the pulse width. Check to make
205 * sure that INIT_B goes low after assertion of PROG_B
206 */
York Sun472d5462013-04-01 11:29:11 -0700207 (*fn->pgm) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000208 udelay (10);
209 ts = get_timer (0);
210 do {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200211 if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200212 printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
wdenk5d3207d2002-08-21 22:08:56 +0000213 " to assert.\n", __FUNCTION__, __LINE__,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200214 CONFIG_SYS_FPGA_WAIT_INIT);
wdenk5d3207d2002-08-21 22:08:56 +0000215 (*fn->abort) (cookie);
216 return FPGA_FAIL;
217 }
218 } while (!(*fn->init) (cookie));
219
York Sun472d5462013-04-01 11:29:11 -0700220 (*fn->pgm) (false, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000221 CONFIG_FPGA_DELAY ();
York Sun472d5462013-04-01 11:29:11 -0700222 (*fn->clk) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000223
224 /*
225 * Start a timer and wait for INIT_B to go high
226 */
227 ts = get_timer (0);
228 do {
229 CONFIG_FPGA_DELAY ();
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200230 if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_INIT) {
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200231 printf ("%s:%d: ** Timeout after %d ticks waiting for INIT"
wdenk5d3207d2002-08-21 22:08:56 +0000232 " to deassert.\n", __FUNCTION__, __LINE__,
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200233 CONFIG_SYS_FPGA_WAIT_INIT);
wdenk5d3207d2002-08-21 22:08:56 +0000234 (*fn->abort) (cookie);
235 return FPGA_FAIL;
236 }
237 } while ((*fn->init) (cookie) && (*fn->busy) (cookie));
238
York Sun472d5462013-04-01 11:29:11 -0700239 (*fn->wr) (true, true, cookie);
240 (*fn->cs) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000241
242 udelay (10000);
243
244 /*
245 * Load the data byte by byte
246 */
247 while (bytecount < bsize) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200248#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
wdenk5d3207d2002-08-21 22:08:56 +0000249 if (ctrlc ()) {
250 (*fn->abort) (cookie);
251 return FPGA_FAIL;
252 }
253#endif
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200254
255 if ((*fn->done) (cookie) == FPGA_SUCCESS) {
256 PRINTF ("%s:%d:done went active early, bytecount = %d\n",
257 __FUNCTION__, __LINE__, bytecount);
258 break;
259 }
260
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200261#ifdef CONFIG_SYS_FPGA_CHECK_ERROR
wdenk5d3207d2002-08-21 22:08:56 +0000262 if ((*fn->init) (cookie)) {
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200263 printf ("\n%s:%d: ** Error: INIT asserted during"
wdenk5d3207d2002-08-21 22:08:56 +0000264 " configuration\n", __FUNCTION__, __LINE__);
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200265 printf ("%d = buffer offset, %d = buffer size\n",
266 bytecount, bsize);
wdenk5d3207d2002-08-21 22:08:56 +0000267 (*fn->abort) (cookie);
268 return FPGA_FAIL;
269 }
270#endif
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200271
York Sun472d5462013-04-01 11:29:11 -0700272 (*fn->wdata) (data[bytecount++], true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000273 CONFIG_FPGA_DELAY ();
274
275 /*
276 * Cycle the clock pin
277 */
York Sun472d5462013-04-01 11:29:11 -0700278 (*fn->clk) (false, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000279 CONFIG_FPGA_DELAY ();
York Sun472d5462013-04-01 11:29:11 -0700280 (*fn->clk) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000281
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200282#ifdef CONFIG_SYS_FPGA_CHECK_BUSY
wdenk5d3207d2002-08-21 22:08:56 +0000283 ts = get_timer (0);
284 while ((*fn->busy) (cookie)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200285 if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_BUSY) {
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200286 printf ("%s:%d: ** Timeout after %d ticks waiting for"
wdenk5d3207d2002-08-21 22:08:56 +0000287 " BUSY to deassert\n",
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200288 __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_BUSY);
wdenk5d3207d2002-08-21 22:08:56 +0000289 (*fn->abort) (cookie);
290 return FPGA_FAIL;
291 }
292 }
293#endif
294
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200295#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000296 if (bytecount % (bsize / 40) == 0)
297 putc ('.');
298#endif
299 }
300
301 /*
302 * Finished writing the data; deassert FPGA CS_B and WRITE_B signals.
303 */
304 CONFIG_FPGA_DELAY ();
York Sun472d5462013-04-01 11:29:11 -0700305 (*fn->cs) (false, true, cookie);
306 (*fn->wr) (false, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000307
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200308#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000309 putc ('\n');
310#endif
311
312 /*
313 * Check for successful configuration. FPGA INIT_B and DONE should
314 * both be high upon successful configuration.
315 */
316 ts = get_timer (0);
317 ret_val = FPGA_SUCCESS;
318 while (((*fn->done) (cookie) == FPGA_FAIL) || (*fn->init) (cookie)) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200319 if (get_timer (ts) > CONFIG_SYS_FPGA_WAIT_CONFIG) {
Wolfgang Denk9a9200b2005-09-24 23:41:00 +0200320 printf ("%s:%d: ** Timeout after %d ticks waiting for DONE to"
wdenk5d3207d2002-08-21 22:08:56 +0000321 "assert and INIT to deassert\n",
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200322 __FUNCTION__, __LINE__, CONFIG_SYS_FPGA_WAIT_CONFIG);
wdenk5d3207d2002-08-21 22:08:56 +0000323 (*fn->abort) (cookie);
324 ret_val = FPGA_FAIL;
325 break;
326 }
327 }
328
329 if (ret_val == FPGA_SUCCESS) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200330#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000331 printf ("Initialization of FPGA device %d complete\n", cookie);
332#endif
333 /*
334 * Run the post configuration function if there is one.
335 */
336 if (*fn->post) {
337 (*fn->post) (cookie);
338 }
339 } else {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200340#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000341 printf ("** Initialization of FPGA device %d FAILED\n",
342 cookie);
343#endif
344 }
345 } else {
346 printf ("%s:%d: NULL Interface function table!\n",
347 __FUNCTION__, __LINE__);
348 }
349 return ret_val;
350}
351
352/*
353 * Read the FPGA configuration data
354 */
Michal Simekf8c1be92014-03-13 12:49:21 +0100355static int virtex2_ssm_dump(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +0000356{
357 int ret_val = FPGA_FAIL;
Michal Simekd9071ce2014-03-13 11:33:36 +0100358 xilinx_virtex2_slave_selectmap_fns *fn = desc->iface_fns;
wdenk5d3207d2002-08-21 22:08:56 +0000359
360 if (fn) {
361 unsigned char *data = (unsigned char *) buf;
362 size_t bytecount = 0;
363 int cookie = desc->cookie;
364
365 printf ("Starting Dump of FPGA Device %d...\n", cookie);
366
York Sun472d5462013-04-01 11:29:11 -0700367 (*fn->cs) (true, true, cookie);
368 (*fn->clk) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000369
370 while (bytecount < bsize) {
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200371#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
wdenk5d3207d2002-08-21 22:08:56 +0000372 if (ctrlc ()) {
373 (*fn->abort) (cookie);
374 return FPGA_FAIL;
375 }
376#endif
377 /*
378 * Cycle the clock and read the data
379 */
York Sun472d5462013-04-01 11:29:11 -0700380 (*fn->clk) (false, true, cookie);
381 (*fn->clk) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000382 (*fn->rdata) (&(data[bytecount++]), cookie);
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200383#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000384 if (bytecount % (bsize / 40) == 0)
385 putc ('.');
386#endif
387 }
388
389 /*
390 * Deassert CS_B and cycle the clock to deselect the device.
391 */
York Sun472d5462013-04-01 11:29:11 -0700392 (*fn->cs) (false, false, cookie);
393 (*fn->clk) (false, true, cookie);
394 (*fn->clk) (true, true, cookie);
wdenk5d3207d2002-08-21 22:08:56 +0000395
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200396#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
wdenk5d3207d2002-08-21 22:08:56 +0000397 putc ('\n');
398#endif
399 puts ("Done.\n");
400 } else {
401 printf ("%s:%d: NULL Interface function table!\n",
402 __FUNCTION__, __LINE__);
403 }
404 return ret_val;
405}
406
Michal Simekf8c1be92014-03-13 12:49:21 +0100407static int virtex2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +0000408{
409 printf ("%s: Slave Serial Loading is unsupported\n", __FUNCTION__);
410 return FPGA_FAIL;
411}
412
Michal Simekf8c1be92014-03-13 12:49:21 +0100413static int virtex2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize)
wdenk5d3207d2002-08-21 22:08:56 +0000414{
415 printf ("%s: Slave Serial Dumping is unsupported\n", __FUNCTION__);
416 return FPGA_FAIL;
417}
418
wdenk5d3207d2002-08-21 22:08:56 +0000419/* vim: set ts=4 tw=78: */