|
@@ -35,8 +35,17 @@
|
35
|
35
|
|
36
|
36
|
#include "etherboot.h"
|
37
|
37
|
#include "timer.h"
|
|
38
|
+#include "io.h"
|
38
|
39
|
#include "isapnp.h"
|
39
|
40
|
|
|
41
|
+/*
|
|
42
|
+ * Ensure that there is sufficient space in the shared dev_bus
|
|
43
|
+ * structure for a struct isapnp_device.
|
|
44
|
+ *
|
|
45
|
+ */
|
|
46
|
+DEV_BUS( struct isapnp_device, isapnp_dev );
|
|
47
|
+static char isapnp_magic[0]; /* guaranteed unique symbol */
|
|
48
|
+
|
40
|
49
|
/*
|
41
|
50
|
* We can have only one ISAPnP bus in a system. Once the read port is
|
42
|
51
|
* known and all cards have been allocated CSNs, there's nothing to be
|
|
@@ -51,8 +60,6 @@
|
51
|
60
|
static uint16_t isapnp_read_port;
|
52
|
61
|
static uint16_t isapnp_max_csn;
|
53
|
62
|
|
54
|
|
-static const char initdata[] = INITDATA;
|
55
|
|
-
|
56
|
63
|
/*
|
57
|
64
|
* ISAPnP utility functions
|
58
|
65
|
*
|
|
@@ -66,13 +73,18 @@ static inline void isapnp_write_data ( uint8_t data ) {
|
66
|
73
|
outb ( data, ISAPNP_WRITE_DATA );
|
67
|
74
|
}
|
68
|
75
|
|
|
76
|
+static inline uint8_t isapnp_read_data ( void ) {
|
|
77
|
+ return inb ( isapnp_read_port );
|
|
78
|
+}
|
|
79
|
+
|
69
|
80
|
static inline void isapnp_write_byte ( uint8_t address, uint8_t value ) {
|
70
|
81
|
isapnp_write_address ( address );
|
71
|
82
|
isapnp_write_data ( value );
|
72
|
83
|
}
|
73
|
84
|
|
74
|
|
-static inline uint8_t isapnp_read_data ( void ) {
|
75
|
|
- return inb ( isapnp_read_port );
|
|
85
|
+static inline uint8_t isapnp_read_byte ( uint8_t address ) {
|
|
86
|
+ isapnp_write_address ( address );
|
|
87
|
+ return isapnp_read_data ();
|
76
|
88
|
}
|
77
|
89
|
|
78
|
90
|
static inline void isapnp_set_read_port ( void ) {
|
|
@@ -95,10 +107,32 @@ static inline void isapnp_wake ( uint8_t csn ) {
|
95
|
107
|
isapnp_write_byte ( ISAPNP_WAKE, csn );
|
96
|
108
|
}
|
97
|
109
|
|
|
110
|
+static inline uint8_t isapnp_read_resourcedata ( void ) {
|
|
111
|
+ return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
|
|
112
|
+}
|
|
113
|
+
|
|
114
|
+static inline uint8_t isapnp_read_status ( void ) {
|
|
115
|
+ return isapnp_read_byte ( ISAPNP_STATUS );
|
|
116
|
+}
|
|
117
|
+
|
98
|
118
|
static inline void isapnp_write_csn ( uint8_t csn ) {
|
99
|
119
|
isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
|
100
|
120
|
}
|
101
|
121
|
|
|
122
|
+static inline void isapnp_logicaldevice ( uint8_t logdev ) {
|
|
123
|
+ isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
|
|
124
|
+}
|
|
125
|
+
|
|
126
|
+static inline void isapnp_activate ( uint8_t logdev ) {
|
|
127
|
+ isapnp_logicaldevice ( logdev );
|
|
128
|
+ isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
|
|
129
|
+}
|
|
130
|
+
|
|
131
|
+static inline void isapnp_deactivate ( uint8_t logdev ) {
|
|
132
|
+ isapnp_logicaldevice ( logdev );
|
|
133
|
+ isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
|
|
134
|
+}
|
|
135
|
+
|
102
|
136
|
/*
|
103
|
137
|
* The linear feedback shift register as described in Appendix B of
|
104
|
138
|
* the PnP ISA spec. The hardware implementation uses eight D-type
|
|
@@ -153,6 +187,42 @@ static uint8_t isapnp_checksum ( union isapnp_identifier *identifier ) {
|
153
|
187
|
return lfsr;
|
154
|
188
|
}
|
155
|
189
|
|
|
190
|
+/*
|
|
191
|
+ * Read a byte of resource data from the current location
|
|
192
|
+ *
|
|
193
|
+ */
|
|
194
|
+static inline uint8_t isapnp_peek_byte ( void ) {
|
|
195
|
+ int i;
|
|
196
|
+
|
|
197
|
+ /* Wait for data to be ready */
|
|
198
|
+ for ( i = 0 ; i < 20 ; i ++ ) {
|
|
199
|
+ if ( isapnp_read_status() & 0x01 ) {
|
|
200
|
+ /* Byte ready - read it */
|
|
201
|
+ return isapnp_read_resourcedata();
|
|
202
|
+ }
|
|
203
|
+ udelay ( 100 );
|
|
204
|
+ }
|
|
205
|
+ /* Data never became ready - return 0xff */
|
|
206
|
+ return 0xff;
|
|
207
|
+}
|
|
208
|
+
|
|
209
|
+/*
|
|
210
|
+ * Read n bytes of resource data from the current location. If buf is
|
|
211
|
+ * NULL, discard data.
|
|
212
|
+ *
|
|
213
|
+ */
|
|
214
|
+static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
|
|
215
|
+ unsigned int i;
|
|
216
|
+ uint8_t byte;
|
|
217
|
+
|
|
218
|
+ for ( i = 0 ; i < bytes ; i++) {
|
|
219
|
+ byte = isapnp_peek_byte();
|
|
220
|
+ if ( buf ) {
|
|
221
|
+ buf[i] = byte;
|
|
222
|
+ }
|
|
223
|
+ }
|
|
224
|
+}
|
|
225
|
+
|
156
|
226
|
/*
|
157
|
227
|
* Try isolating ISAPnP cards at the current read port. Return the
|
158
|
228
|
* number of ISAPnP cards found.
|
|
@@ -277,146 +347,6 @@ static void isapnp_isolate ( void ) {
|
277
|
347
|
}
|
278
|
348
|
}
|
279
|
349
|
|
280
|
|
-
|
281
|
|
-
|
282
|
|
-
|
283
|
|
-
|
284
|
|
-
|
285
|
|
-/*
|
286
|
|
- * Build device list for all present ISA PnP devices.
|
287
|
|
- */
|
288
|
|
-static int isapnp_build_device_list(void)
|
289
|
|
-{
|
290
|
|
- int csn, device, vendor, serial;
|
291
|
|
- unsigned char header[9], checksum;
|
292
|
|
- for (csn = 1; csn <= 10; csn++) {
|
293
|
|
- Wake(csn);
|
294
|
|
- isapnp_peek(header, 9);
|
295
|
|
- checksum = isapnp_checksum(header);
|
296
|
|
-#ifdef EDEBUG
|
297
|
|
- printf
|
298
|
|
- ("vendor: 0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX\n",
|
299
|
|
- header[0], header[1], header[2], header[3], header[4],
|
300
|
|
- header[5], header[6], header[7], header[8]);
|
301
|
|
- printf("checksum = 0xhX\n", checksum);
|
302
|
|
-#endif
|
303
|
|
- /* Don't be strict on the checksum, here !
|
304
|
|
- e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7) */
|
305
|
|
- if (header[8] == 0);
|
306
|
|
- else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */
|
307
|
|
- continue;
|
308
|
|
-
|
309
|
|
- vendor = (header[1] << 8) | header[0];
|
310
|
|
- device = (header[3] << 8) | header[2];
|
311
|
|
- serial =
|
312
|
|
- (header[7] << 24) | (header[6] << 16) | (header[5] <<
|
313
|
|
- 8) |
|
314
|
|
- header[4];
|
315
|
|
- if (vendor == 0x6D50)
|
316
|
|
- if (device == 0x5150) {
|
317
|
|
- printf
|
318
|
|
- ("\nFound 3Com 3c515 PNP Card!\n Vendor ID: 0x%hX, Device ID: 0x%hX, Serial Num: 0x%hX\n",
|
319
|
|
- vendor, device, serial);
|
320
|
|
- pnp_card_csn = csn;
|
321
|
|
- }
|
322
|
|
- isapnp_checksum_value = 0x00;
|
323
|
|
- }
|
324
|
|
- return 0;
|
325
|
|
-}
|
326
|
|
-
|
327
|
|
-int Config(int csn)
|
328
|
|
-{
|
329
|
|
-#define TIMEOUT_PNP 100
|
330
|
|
- unsigned char id[IDENT_LEN];
|
331
|
|
- int i, x;
|
332
|
|
- Wake(csn);
|
333
|
|
- udelay(1000);
|
334
|
|
- for (i = 0; i < IDENT_LEN; i++) {
|
335
|
|
- for (x = 1; x < TIMEOUT_PNP; x++) {
|
336
|
|
- if (STATUS & 1)
|
337
|
|
- break;
|
338
|
|
- udelay(1000);
|
339
|
|
- }
|
340
|
|
- id[i] = RESOURCEDATA;
|
341
|
|
-#ifdef EDEBUG
|
342
|
|
- printf(" 0x%hX ", id[i]);
|
343
|
|
-#endif
|
344
|
|
- }
|
345
|
|
-#ifdef EDEBUG
|
346
|
|
- printf("Got The status bit\n");
|
347
|
|
-#endif
|
348
|
|
- /*Set Logical Device Register active */
|
349
|
|
- LOGICALDEVICENUMBER;
|
350
|
|
- /* Specify the first logical device */
|
351
|
|
- WRITE_DATA(0);
|
352
|
|
-
|
353
|
|
-
|
354
|
|
- /* Apparently just activating the card is enough
|
355
|
|
- for Etherboot to detect it. Why bother with the
|
356
|
|
- following code. Left in place in case it is
|
357
|
|
- later required */
|
358
|
|
-/*==========================================*/
|
359
|
|
- /* set DMA */
|
360
|
|
-/* ADDRESS(0x74 + 0);
|
361
|
|
- WRITE_DATA(7); */
|
362
|
|
-
|
363
|
|
- /*Set IRQ */
|
364
|
|
-/* udelay(1000);
|
365
|
|
- ADDRESS(0x70 + (0 << 1));
|
366
|
|
- WRITE_DATA(9);
|
367
|
|
- udelay(1000); */
|
368
|
|
-/*=============================================*/
|
369
|
|
- /*Activate */
|
370
|
|
- ACTIVATE;
|
371
|
|
- WRITE_DATA(1);
|
372
|
|
- udelay(250);
|
373
|
|
- /* Ask for access to the Wait for Key command - ConfigControl register */
|
374
|
|
- CONFIGCONTROL;
|
375
|
|
- /* Write the Wait for Key Command to the ConfigControl Register */
|
376
|
|
- WRITE_DATA(CONFIG_WAIT_FOR_KEY);
|
377
|
|
- /* As per doc. Two Write cycles of 0x00 required befor the Initialization key is sent */
|
378
|
|
- ADDRESS(0);
|
379
|
|
- ADDRESS(0);
|
380
|
|
-
|
381
|
|
- return 1;
|
382
|
|
-}
|
383
|
|
-
|
384
|
|
-
|
385
|
|
-static void isapnp_peek(unsigned char *data, int bytes)
|
386
|
|
-{
|
387
|
|
- int i, j;
|
388
|
|
- unsigned char d = 0;
|
389
|
|
-
|
390
|
|
- for (i = 1; i <= bytes; i++) {
|
391
|
|
- for (j = 0; j < 20; j++) {
|
392
|
|
- d = STATUS;
|
393
|
|
- if (d & 1)
|
394
|
|
- break;
|
395
|
|
- udelay(100);
|
396
|
|
- }
|
397
|
|
- if (!(d & 1)) {
|
398
|
|
- if (data != NULL)
|
399
|
|
- *data++ = 0xff;
|
400
|
|
- continue;
|
401
|
|
- }
|
402
|
|
- d = RESOURCEDATA; /* PRESDI */
|
403
|
|
- isapnp_checksum_value += d;
|
404
|
|
- if (data != NULL)
|
405
|
|
- *data++ = d;
|
406
|
|
- }
|
407
|
|
-}
|
408
|
|
-
|
409
|
|
-
|
410
|
|
-
|
411
|
|
-
|
412
|
|
-/*
|
413
|
|
- * Ensure that there is sufficient space in the shared dev_bus
|
414
|
|
- * structure for a struct isapnp_device.
|
415
|
|
- *
|
416
|
|
- */
|
417
|
|
-DEV_BUS( struct isapnp_device, isapnp_dev );
|
418
|
|
-static char isapnp_magic[0]; /* guaranteed unique symbol */
|
419
|
|
-
|
420
|
350
|
/*
|
421
|
351
|
* Fill in parameters for an ISAPnP device based on CSN
|
422
|
352
|
*
|
|
@@ -424,23 +354,45 @@ static char isapnp_magic[0]; /* guaranteed unique symbol */
|
424
|
354
|
*
|
425
|
355
|
*/
|
426
|
356
|
static int fill_isapnp_device ( struct isapnp_device *isapnp ) {
|
427
|
|
-
|
428
|
|
- /*
|
429
|
|
- * Ensure that all ISAPnP cards have CSNs allocated to them,
|
|
357
|
+ union isapnp_identifier identifier;
|
|
358
|
+
|
|
359
|
+ /* Ensure that all ISAPnP cards have CSNs allocated to them,
|
430
|
360
|
* if we haven't already done so.
|
431
|
|
- *
|
432
|
361
|
*/
|
433
|
362
|
if ( ! isapnp_read_port ) {
|
434
|
363
|
isapnp_isolate();
|
435
|
364
|
}
|
436
|
365
|
|
437
|
|
- /* wake csn, read config, send card to sleep */
|
|
366
|
+ /* Wake the specified CSN */
|
|
367
|
+ isapnp_wait_for_key ();
|
|
368
|
+ isapnp_send_key ();
|
|
369
|
+ isapnp_wake ( isapnp->csn );
|
|
370
|
+
|
|
371
|
+ /* Read the identifier and verify the checksum. Allow
|
|
372
|
+ * checksum = 0 to cope with cards that just generate the
|
|
373
|
+ * checksum using the LFSR during serial isolation.
|
|
374
|
+ */
|
|
375
|
+ isapnp_peek ( identifier.bytes, sizeof ( identifier ) );
|
|
376
|
+ if ( ( identifier.checksum != 0 ) &&
|
|
377
|
+ ( identifier.checksum != isapnp_checksum ( &identifier ) ) ) {
|
|
378
|
+ DBG ( "ISAPnP invalid checksum on CSN %hhx "
|
|
379
|
+ "(is %hhx, should be %hhx)\n", isapnp->csn,
|
|
380
|
+ identifier.checksum, isapnp_checksum ( &identifier ) );
|
|
381
|
+ return 0;
|
|
382
|
+ }
|
|
383
|
+
|
|
384
|
+ /* Read information from identifier structure */
|
|
385
|
+ isapnp->vendor_id = identifier.vendor_id;
|
|
386
|
+ isapnp->prod_id = identifier.prod_id;
|
|
387
|
+
|
|
388
|
+ /* Return all cards to Wait for Key state */
|
|
389
|
+ isapnp_wait_for_key ();
|
438
|
390
|
|
439
|
391
|
DBG ( "ISAPnP found CSN %hhx ID %hx:%hx (\"%s\")\n",
|
440
|
392
|
isapnp->csn, isapnp->vendor_id, isapnp->prod_id,
|
441
|
393
|
isa_id_string ( isapnp->vendor_id, isapnp->prod_id ) );
|
442
|
394
|
|
443
|
|
- return 0;
|
|
395
|
+ return 1;
|
444
|
396
|
}
|
445
|
397
|
|
446
|
398
|
/*
|
|
@@ -514,3 +466,45 @@ int find_isapnp_boot_device ( struct dev *dev, struct isapnp_driver *driver ) {
|
514
|
466
|
|
515
|
467
|
return 1;
|
516
|
468
|
}
|
|
469
|
+
|
|
470
|
+/*
|
|
471
|
+ * Activate a logical function on an ISAPnP device
|
|
472
|
+ *
|
|
473
|
+ * This routine simply activates the device in its current
|
|
474
|
+ * configuration. It does not attempt any kind of resource
|
|
475
|
+ * arbitration.
|
|
476
|
+ *
|
|
477
|
+ */
|
|
478
|
+void activate_isapnp_device ( struct isapnp_device *isapnp,
|
|
479
|
+ uint8_t logdev ) {
|
|
480
|
+ /* Wake the device */
|
|
481
|
+ isapnp_wait_for_key ();
|
|
482
|
+ isapnp_send_key ();
|
|
483
|
+ isapnp_wake ( isapnp->csn );
|
|
484
|
+
|
|
485
|
+ /* Select the specified logical device */
|
|
486
|
+ isapnp_activate ( logdev );
|
|
487
|
+ udelay ( 1000 );
|
|
488
|
+
|
|
489
|
+ /* Return all cards to Wait for Key state */
|
|
490
|
+ isapnp_wait_for_key ();
|
|
491
|
+}
|
|
492
|
+
|
|
493
|
+/*
|
|
494
|
+ * Deactivate a logical function on an ISAPnP device
|
|
495
|
+ *
|
|
496
|
+ */
|
|
497
|
+void deactivate_isapnp_device ( struct isapnp_device *isapnp,
|
|
498
|
+ uint8_t logdev ) {
|
|
499
|
+ /* Wake the device */
|
|
500
|
+ isapnp_wait_for_key ();
|
|
501
|
+ isapnp_send_key ();
|
|
502
|
+ isapnp_wake ( isapnp->csn );
|
|
503
|
+
|
|
504
|
+ /* Select the specified logical device */
|
|
505
|
+ isapnp_deactivate ( logdev );
|
|
506
|
+ udelay ( 1000 );
|
|
507
|
+
|
|
508
|
+ /* Return all cards to Wait for Key state */
|
|
509
|
+ isapnp_wait_for_key ();
|
|
510
|
+}
|