blob: 05a14ff103866308682e3842b2ce2488534199a7 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Dirk Eibach50dcf892014-11-13 19:21:18 +01002/*
3 * (C) Copyright 2014
4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc
Dirk Eibach50dcf892014-11-13 19:21:18 +01005 */
6
7#include <common.h>
8#include <command.h>
Simon Glass24b852a2015-11-08 23:47:45 -07009#include <console.h>
Dirk Eibach50dcf892014-11-13 19:21:18 +010010
11#include <gdsys_fpga.h>
12
Mario Sixdf8e5fb2019-03-29 10:18:14 +010013#ifndef CONFIG_GDSYS_LEGACY_DRIVERS
14#include <dm.h>
15#include <misc.h>
16#include <regmap.h>
17#include <board.h>
18
19#include "../../../drivers/misc/gdsys_soc.h"
20#include "../../../drivers/misc/gdsys_ioep.h"
21#include "../../../drivers/misc/ihs_fpga.h"
22
23const int HEADER_WORDS = sizeof(struct io_generic_packet) / 2;
24#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */
25
Mario Sixba757722019-03-29 10:18:13 +010026enum status_print_type {
27 STATUS_LOUD = 0,
28 STATUS_SILENT = 1,
29};
30
Mario Sixdf8e5fb2019-03-29 10:18:14 +010031#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Dirk Eibach50dcf892014-11-13 19:21:18 +010032enum {
Mario Sixdb1d03a2019-03-29 10:18:12 +010033 STATE_TX_PACKET_BUILDING = BIT(0),
34 STATE_TX_TRANSMITTING = BIT(1),
35 STATE_TX_BUFFER_FULL = BIT(2),
36 STATE_TX_ERR = BIT(3),
37 STATE_RECEIVE_TIMEOUT = BIT(4),
38 STATE_PROC_RX_STORE_TIMEOUT = BIT(5),
39 STATE_PROC_RX_RECEIVE_TIMEOUT = BIT(6),
40 STATE_RX_DIST_ERR = BIT(7),
41 STATE_RX_LENGTH_ERR = BIT(8),
42 STATE_RX_FRAME_CTR_ERR = BIT(9),
43 STATE_RX_FCS_ERR = BIT(10),
44 STATE_RX_PACKET_DROPPED = BIT(11),
45 STATE_RX_DATA_LAST = BIT(12),
46 STATE_RX_DATA_FIRST = BIT(13),
47 STATE_RX_DATA_AVAILABLE = BIT(15),
Dirk Eibach50dcf892014-11-13 19:21:18 +010048};
49
50enum {
Mario Sixdb1d03a2019-03-29 10:18:12 +010051 IRQ_CPU_TRANSMITBUFFER_FREE_STATUS = BIT(5),
52 IRQ_CPU_PACKET_TRANSMITTED_EVENT = BIT(6),
53 IRQ_NEW_CPU_PACKET_RECEIVED_EVENT = BIT(7),
54 IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS = BIT(8),
Dirk Eibach50dcf892014-11-13 19:21:18 +010055};
56
Mario Sixdf8e5fb2019-03-29 10:18:14 +010057enum {
58 CTRL_PROC_RECEIVE_ENABLE = BIT(12),
59 CTRL_FLUSH_TRANSMIT_BUFFER = BIT(15),
60};
61
Dirk Eibach50dcf892014-11-13 19:21:18 +010062struct io_generic_packet {
63 u16 target_address;
64 u16 source_address;
65 u8 packet_type;
66 u8 bc;
67 u16 packet_length;
68} __attribute__((__packed__));
Mario Sixdf8e5fb2019-03-29 10:18:14 +010069#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
Dirk Eibach50dcf892014-11-13 19:21:18 +010070
71unsigned long long rx_ctr;
72unsigned long long tx_ctr;
73unsigned long long err_ctr;
Mario Sixdf8e5fb2019-03-29 10:18:14 +010074#ifndef CONFIG_GDSYS_LEGACY_DRIVERS
75struct udevice *dev;
76#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */
Dirk Eibach50dcf892014-11-13 19:21:18 +010077
Mario Sixdf8e5fb2019-03-29 10:18:14 +010078#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Sixba757722019-03-29 10:18:13 +010079static void io_check_status(uint fpga, u16 status, enum status_print_type type)
Dirk Eibach50dcf892014-11-13 19:21:18 +010080{
81 u16 mask = STATE_RX_DIST_ERR | STATE_RX_LENGTH_ERR |
82 STATE_RX_FRAME_CTR_ERR | STATE_RX_FCS_ERR |
83 STATE_RX_PACKET_DROPPED | STATE_TX_ERR;
84
85 if (!(status & mask)) {
86 FPGA_SET_REG(fpga, ep.rx_tx_status, status);
87 return;
88 }
89
90 err_ctr++;
91 FPGA_SET_REG(fpga, ep.rx_tx_status, status);
92
Mario Sixba757722019-03-29 10:18:13 +010093 if (type == STATUS_SILENT)
Dirk Eibach50dcf892014-11-13 19:21:18 +010094 return;
95
96 if (status & STATE_RX_PACKET_DROPPED)
97 printf("RX_PACKET_DROPPED, status %04x\n", status);
98
99 if (status & STATE_RX_DIST_ERR)
100 printf("RX_DIST_ERR\n");
101 if (status & STATE_RX_LENGTH_ERR)
102 printf("RX_LENGTH_ERR\n");
103 if (status & STATE_RX_FRAME_CTR_ERR)
104 printf("RX_FRAME_CTR_ERR\n");
105 if (status & STATE_RX_FCS_ERR)
106 printf("RX_FCS_ERR\n");
107
108 if (status & STATE_TX_ERR)
109 printf("TX_ERR\n");
110}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100111#else
112static void io_check_status(struct udevice *dev, enum status_print_type type)
113{
114 u16 status = 0;
115 int ret;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100116
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100117 ret = misc_call(dev, 0, NULL, 0, &status, 0);
118 if (!ret)
119 return;
120
121 err_ctr++;
122
123 if (type != STATUS_LOUD)
124 return;
125
126 if (status & STATE_RX_PACKET_DROPPED)
127 printf("RX_PACKET_DROPPED, status %04x\n", status);
128
129 if (status & STATE_RX_DIST_ERR)
130 printf("RX_DIST_ERR\n");
131 if (status & STATE_RX_LENGTH_ERR)
132 printf("RX_LENGTH_ERR\n");
133 if (status & STATE_RX_FRAME_CTR_ERR)
134 printf("RX_FRAME_CTR_ERR\n");
135 if (status & STATE_RX_FCS_ERR)
136 printf("RX_FCS_ERR\n");
137
138 if (status & STATE_TX_ERR)
139 printf("TX_ERR\n");
140}
141#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
142
143#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Sixdb1d03a2019-03-29 10:18:12 +0100144static void io_send(uint fpga, uint size)
Dirk Eibach50dcf892014-11-13 19:21:18 +0100145{
Mario Sixdb1d03a2019-03-29 10:18:12 +0100146 uint k;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100147 struct io_generic_packet packet = {
148 .source_address = 1,
149 .packet_type = 1,
150 .packet_length = size,
151 };
152 u16 *p = (u16 *)&packet;
153
154 for (k = 0; k < sizeof(packet) / 2; ++k)
155 FPGA_SET_REG(fpga, ep.transmit_data, *p++);
156
157 for (k = 0; k < (size + 1) / 2; ++k)
158 FPGA_SET_REG(fpga, ep.transmit_data, k);
159
160 FPGA_SET_REG(fpga, ep.rx_tx_control,
161 CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
162
163 tx_ctr++;
164}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100165#else
166static void io_send(struct udevice *dev, uint size)
167{
168 uint k;
169 u16 buffer[HEADER_WORDS + 128];
170 struct io_generic_packet header = {
171 .source_address = 1,
172 .packet_type = 1,
173 .packet_length = size,
174 };
175 const uint words = (size + 1) / 2;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100176
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100177 memcpy(buffer, &header, 2 * HEADER_WORDS);
178 for (k = 0; k < words; ++k)
179 buffer[k + HEADER_WORDS] = (2 * k + 1) + ((2 * k) << 8);
180
181 misc_write(dev, 0, buffer, HEADER_WORDS + words);
182
183 tx_ctr++;
184}
185#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
186
187#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Sixdb1d03a2019-03-29 10:18:12 +0100188static void io_receive(uint fpga)
Dirk Eibach50dcf892014-11-13 19:21:18 +0100189{
Dirk Eibach50dcf892014-11-13 19:21:18 +0100190 u16 rx_tx_status;
191
192 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
193
194 while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
195 u16 rx;
196
197 if (rx_tx_status & STATE_RX_DATA_LAST)
198 rx_ctr++;
199
200 FPGA_GET_REG(fpga, ep.receive_data, &rx);
201
202 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
Dirk Eibach50dcf892014-11-13 19:21:18 +0100203 }
204}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100205#else
206static void io_receive(struct udevice *dev)
207{
208 u16 buffer[HEADER_WORDS + 128];
Dirk Eibach50dcf892014-11-13 19:21:18 +0100209
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100210 if (!misc_read(dev, 0, buffer, 0))
211 rx_ctr++;
212}
213#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
214
215#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Mario Sixdb1d03a2019-03-29 10:18:12 +0100216static void io_reflect(uint fpga)
Dirk Eibach50dcf892014-11-13 19:21:18 +0100217{
218 u16 buffer[128];
219
Mario Sixdb1d03a2019-03-29 10:18:12 +0100220 uint k = 0;
221 uint n;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100222 u16 rx_tx_status;
223
224 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
225
226 while (rx_tx_status & STATE_RX_DATA_AVAILABLE) {
227 FPGA_GET_REG(fpga, ep.receive_data, &buffer[k++]);
228 if (rx_tx_status & STATE_RX_DATA_LAST)
229 break;
230
231 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
232 }
233
234 if (!k)
235 return;
236
237 for (n = 0; n < k; ++n)
238 FPGA_SET_REG(fpga, ep.transmit_data, buffer[n]);
239
240 FPGA_SET_REG(fpga, ep.rx_tx_control,
241 CTRL_PROC_RECEIVE_ENABLE | CTRL_FLUSH_TRANSMIT_BUFFER);
242
243 tx_ctr++;
244}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100245#else
246static void io_reflect(struct udevice *dev)
247{
248 u16 buffer[HEADER_WORDS + 128];
249 struct io_generic_packet *header;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100250
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100251 if (misc_read(dev, 0, buffer, 0))
252 return;
253
254 header = (struct io_generic_packet *)&buffer;
255
256 misc_write(dev, 0, buffer, HEADER_WORDS + header->packet_length);
257}
258#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
259
260#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Dirk Eibach50dcf892014-11-13 19:21:18 +0100261/*
262 * FPGA io-endpoint reflector
263 *
264 * Syntax:
265 * ioreflect {fpga} {reportrate}
266 */
267int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
268{
Mario Sixdb1d03a2019-03-29 10:18:12 +0100269 uint fpga;
270 uint rate = 0;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100271 unsigned long long last_seen = 0;
272
273 if (argc < 2)
274 return CMD_RET_USAGE;
275
276 fpga = simple_strtoul(argv[1], NULL, 10);
277
278 /*
279 * If another parameter, it is the report rate in packets.
280 */
281 if (argc > 2)
282 rate = simple_strtoul(argv[2], NULL, 10);
283
Mario Sixdb1d03a2019-03-29 10:18:12 +0100284 /* Enable receive path */
Dirk Eibach50dcf892014-11-13 19:21:18 +0100285 FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
286
Mario Sixdb1d03a2019-03-29 10:18:12 +0100287 /* Set device address to dummy 1*/
Dirk Eibach50dcf892014-11-13 19:21:18 +0100288 FPGA_SET_REG(fpga, ep.device_address, 1);
289
290 rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
291
292 while (1) {
293 u16 top_int;
294 u16 rx_tx_status;
295
296 FPGA_GET_REG(fpga, top_interrupt, &top_int);
297 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
298
Mario Sixba757722019-03-29 10:18:13 +0100299 io_check_status(fpga, rx_tx_status, STATUS_SILENT);
Dirk Eibach50dcf892014-11-13 19:21:18 +0100300 if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) &&
301 (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS))
302 io_reflect(fpga);
303
304 if (rate) {
305 if (!(tx_ctr % rate) && (tx_ctr != last_seen))
306 printf("refl %llu, err %llu\n", tx_ctr,
307 err_ctr);
308 last_seen = tx_ctr;
309 }
310
311 if (ctrlc())
312 break;
313 }
314
315 return 0;
316}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100317#else
318/*
319 * FPGA io-endpoint reflector
320 *
321 * Syntax:
322 * ioreflect {reportrate}
323 */
324int do_ioreflect(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
325{
326 struct udevice *fpga;
327 struct regmap *map;
328 uint rate = 0;
329 unsigned long long last_seen = 0;
330
331 if (!dev) {
332 printf("No device selected\n");
333 return 1;
334 }
335
336 gdsys_soc_get_fpga(dev, &fpga);
337 regmap_init_mem(dev_ofnode(dev), &map);
338
339 /* Enable receive path */
340 misc_set_enabled(dev, true);
341
342 rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
343
344 while (1) {
345 uint top_int;
346
347 ihs_fpga_get(map, top_interrupt, &top_int);
348 io_check_status(dev, STATUS_SILENT);
349 if ((top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS) &&
350 (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS))
351 io_reflect(dev);
352
353 if (rate) {
354 if (!(tx_ctr % rate) && (tx_ctr != last_seen))
355 printf("refl %llu, err %llu\n", tx_ctr,
356 err_ctr);
357 last_seen = tx_ctr;
358 }
359
360 if (ctrlc())
361 break;
362 }
363
364 return 0;
365}
366#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
Dirk Eibach50dcf892014-11-13 19:21:18 +0100367
Mario Sixdb1d03a2019-03-29 10:18:12 +0100368#define DISP_LINE_LEN 16
369
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100370#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Dirk Eibach50dcf892014-11-13 19:21:18 +0100371/*
372 * FPGA io-endpoint looptest
373 *
374 * Syntax:
375 * ioloop {fpga} {size} {rate}
376 */
Dirk Eibach50dcf892014-11-13 19:21:18 +0100377int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
378{
Mario Sixdb1d03a2019-03-29 10:18:12 +0100379 uint fpga;
380 uint size;
381 uint rate = 0;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100382
383 if (argc < 3)
384 return CMD_RET_USAGE;
385
386 /*
387 * FPGA is specified since argc > 2
388 */
389 fpga = simple_strtoul(argv[1], NULL, 10);
390
391 /*
392 * packet size is specified since argc > 2
393 */
394 size = simple_strtoul(argv[2], NULL, 10);
395
396 /*
397 * If another parameter, it is the test rate in packets per second.
398 */
399 if (argc > 3)
400 rate = simple_strtoul(argv[3], NULL, 10);
401
402 /* enable receive path */
403 FPGA_SET_REG(fpga, ep.rx_tx_control, CTRL_PROC_RECEIVE_ENABLE);
404
405 /* set device address to dummy 1*/
406 FPGA_SET_REG(fpga, ep.device_address, 1);
407
408 rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
409
410 while (1) {
411 u16 top_int;
412 u16 rx_tx_status;
413
414 FPGA_GET_REG(fpga, top_interrupt, &top_int);
415 FPGA_GET_REG(fpga, ep.rx_tx_status, &rx_tx_status);
416
Mario Sixba757722019-03-29 10:18:13 +0100417 io_check_status(fpga, rx_tx_status, STATUS_LOUD);
Dirk Eibach50dcf892014-11-13 19:21:18 +0100418 if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)
419 io_send(fpga, size);
420 if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS)
421 io_receive(fpga);
422
423 if (rate) {
424 if (ctrlc())
425 break;
426 udelay(1000000 / rate);
427 if (!(tx_ctr % rate))
Mario Sixdb1d03a2019-03-29 10:18:12 +0100428 printf("d %llu, tx %llu, rx %llu, err %llu\n",
Dirk Eibach50dcf892014-11-13 19:21:18 +0100429 tx_ctr - rx_ctr, tx_ctr, rx_ctr,
430 err_ctr);
431 }
432 }
433
434 return 0;
435}
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100436#else
437/*
438 * FPGA io-endpoint looptest
439 *
440 * Syntax:
441 * ioloop {size} {rate}
442 */
443int do_ioloop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
444{
445 uint size;
446 uint rate = 0;
447 struct udevice *fpga;
448 struct regmap *map;
Dirk Eibach50dcf892014-11-13 19:21:18 +0100449
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100450 if (!dev) {
451 printf("No device selected\n");
452 return 1;
453 }
454
455 gdsys_soc_get_fpga(dev, &fpga);
456 regmap_init_mem(dev_ofnode(dev), &map);
457
458 if (argc < 2)
459 return CMD_RET_USAGE;
460
461 /*
462 * packet size is specified since argc > 1
463 */
464 size = simple_strtoul(argv[2], NULL, 10);
465
466 /*
467 * If another parameter, it is the test rate in packets per second.
468 */
469 if (argc > 2)
470 rate = simple_strtoul(argv[3], NULL, 10);
471
472 /* Enable receive path */
473 misc_set_enabled(dev, true);
474
475 rx_ctr = 0; tx_ctr = 0; err_ctr = 0;
476
477 while (1) {
478 uint top_int;
479
480 if (ctrlc())
481 break;
482
483 ihs_fpga_get(map, top_interrupt, &top_int);
484
485 io_check_status(dev, STATUS_LOUD);
486 if (top_int & IRQ_CPU_TRANSMITBUFFER_FREE_STATUS)
487 io_send(dev, size);
488 if (top_int & IRQ_CPU_RECEIVE_DATA_AVAILABLE_STATUS)
489 io_receive(dev);
490
491 if (rate) {
492 udelay(1000000 / rate);
493 if (!(tx_ctr % rate))
494 printf("d %llu, tx %llu, rx %llu, err %llu\n",
495 tx_ctr - rx_ctr, tx_ctr, rx_ctr,
496 err_ctr);
497 }
498 }
499 return 0;
500}
501#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */
502
503#ifndef CONFIG_GDSYS_LEGACY_DRIVERS
504int do_iodev(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
505{
506 struct udevice *ioep = NULL;
507 struct udevice *board;
508 char name[8];
509 int ret;
510
511 if (board_get(&board))
512 return CMD_RET_FAILURE;
513
514 if (argc > 1) {
515 int i = simple_strtoul(argv[1], NULL, 10);
516
517 snprintf(name, sizeof(name), "ioep%d", i);
518
519 ret = uclass_get_device_by_phandle(UCLASS_MISC, board, name, &ioep);
520
521 if (ret || !ioep) {
522 printf("Invalid IOEP %d\n", i);
523 return CMD_RET_FAILURE;
524 }
525
526 dev = ioep;
527 } else {
528 int i = 0;
529
530 while (1) {
531 snprintf(name, sizeof(name), "ioep%d", i);
532
533 ret = uclass_get_device_by_phandle(UCLASS_MISC, board, name, &ioep);
534
535 if (ret || !ioep)
536 break;
537
538 printf("IOEP %d:\t%s\n", i++, ioep->name);
539 }
540
541 if (dev)
542 printf("\nSelected IOEP: %s\n", dev->name);
543 else
544 puts("\nNo IOEP selected.\n");
545 }
546
547 return 0;
548}
549#endif /* !CONFIG_GDSYS_LEGACY_DRIVERS */
550
551#ifdef CONFIG_GDSYS_LEGACY_DRIVERS
Dirk Eibach50dcf892014-11-13 19:21:18 +0100552U_BOOT_CMD(
553 ioloop, 4, 0, do_ioloop,
554 "fpga io-endpoint looptest",
555 "fpga packetsize [packets/sec]"
556);
557
558U_BOOT_CMD(
559 ioreflect, 3, 0, do_ioreflect,
560 "fpga io-endpoint reflector",
561 "fpga reportrate"
562);
Mario Sixdf8e5fb2019-03-29 10:18:14 +0100563#else
564U_BOOT_CMD(
565 ioloop, 3, 0, do_ioloop,
566 "fpga io-endpoint looptest",
567 "packetsize [packets/sec]"
568);
569
570U_BOOT_CMD(
571 ioreflect, 2, 0, do_ioreflect,
572 "fpga io-endpoint reflector",
573 "reportrate"
574);
575
576U_BOOT_CMD(
577 iodev, 2, 0, do_iodev,
578 "fpga io-endpoint listing/selection",
579 "[ioep device to select]"
580);
581#endif /* CONFIG_GDSYS_LEGACY_DRIVERS */