Statistics
| Branch: | Revision:

root / hw / smc91c111.c @ 50132156

History | View | Annotate | Download (20 kB)

1
/*
2
 * SMSC 91C111 Ethernet interface emulation
3
 *
4
 * Copyright (c) 2005 CodeSourcery, LLC.
5
 * Written by Paul Brook
6
 *
7
 * This code is licenced under the GPL
8
 */
9

    
10
#include "sysbus.h"
11
#include "net.h"
12
#include "devices.h"
13
/* For crc32 */
14
#include <zlib.h>
15

    
16
/* Number of 2k memory pages available.  */
17
#define NUM_PACKETS 4
18

    
19
typedef struct {
20
    SysBusDevice busdev;
21
    VLANClientState *vc;
22
    NICConf conf;
23
    uint16_t tcr;
24
    uint16_t rcr;
25
    uint16_t cr;
26
    uint16_t ctr;
27
    uint16_t gpr;
28
    uint16_t ptr;
29
    uint16_t ercv;
30
    qemu_irq irq;
31
    int bank;
32
    int packet_num;
33
    int tx_alloc;
34
    /* Bitmask of allocated packets.  */
35
    int allocated;
36
    int tx_fifo_len;
37
    int tx_fifo[NUM_PACKETS];
38
    int rx_fifo_len;
39
    int rx_fifo[NUM_PACKETS];
40
    int tx_fifo_done_len;
41
    int tx_fifo_done[NUM_PACKETS];
42
    /* Packet buffer memory.  */
43
    uint8_t data[NUM_PACKETS][2048];
44
    uint8_t int_level;
45
    uint8_t int_mask;
46
    int mmio_index;
47
} smc91c111_state;
48

    
49
#define RCR_SOFT_RST  0x8000
50
#define RCR_STRIP_CRC 0x0200
51
#define RCR_RXEN      0x0100
52

    
53
#define TCR_EPH_LOOP  0x2000
54
#define TCR_NOCRC     0x0100
55
#define TCR_PAD_EN    0x0080
56
#define TCR_FORCOL    0x0004
57
#define TCR_LOOP      0x0002
58
#define TCR_TXEN      0x0001
59

    
60
#define INT_MD        0x80
61
#define INT_ERCV      0x40
62
#define INT_EPH       0x20
63
#define INT_RX_OVRN   0x10
64
#define INT_ALLOC     0x08
65
#define INT_TX_EMPTY  0x04
66
#define INT_TX        0x02
67
#define INT_RCV       0x01
68

    
69
#define CTR_AUTO_RELEASE  0x0800
70
#define CTR_RELOAD        0x0002
71
#define CTR_STORE         0x0001
72

    
73
#define RS_ALGNERR      0x8000
74
#define RS_BRODCAST     0x4000
75
#define RS_BADCRC       0x2000
76
#define RS_ODDFRAME     0x1000
77
#define RS_TOOLONG      0x0800
78
#define RS_TOOSHORT     0x0400
79
#define RS_MULTICAST    0x0001
80

    
81
/* Update interrupt status.  */
82
static void smc91c111_update(smc91c111_state *s)
83
{
84
    int level;
85

    
86
    if (s->tx_fifo_len == 0)
87
        s->int_level |= INT_TX_EMPTY;
88
    if (s->tx_fifo_done_len != 0)
89
        s->int_level |= INT_TX;
90
    level = (s->int_level & s->int_mask) != 0;
91
    qemu_set_irq(s->irq, level);
92
}
93

    
94
/* Try to allocate a packet.  Returns 0x80 on failure.  */
95
static int smc91c111_allocate_packet(smc91c111_state *s)
96
{
97
    int i;
98
    if (s->allocated == (1 << NUM_PACKETS) - 1) {
99
        return 0x80;
100
    }
101

    
102
    for (i = 0; i < NUM_PACKETS; i++) {
103
        if ((s->allocated & (1 << i)) == 0)
104
            break;
105
    }
106
    s->allocated |= 1 << i;
107
    return i;
108
}
109

    
110

    
111
/* Process a pending TX allocate.  */
112
static void smc91c111_tx_alloc(smc91c111_state *s)
113
{
114
    s->tx_alloc = smc91c111_allocate_packet(s);
115
    if (s->tx_alloc == 0x80)
116
        return;
117
    s->int_level |= INT_ALLOC;
118
    smc91c111_update(s);
119
}
120

    
121
/* Remove and item from the RX FIFO.  */
122
static void smc91c111_pop_rx_fifo(smc91c111_state *s)
123
{
124
    int i;
125

    
126
    s->rx_fifo_len--;
127
    if (s->rx_fifo_len) {
128
        for (i = 0; i < s->rx_fifo_len; i++)
129
            s->rx_fifo[i] = s->rx_fifo[i + 1];
130
        s->int_level |= INT_RCV;
131
    } else {
132
        s->int_level &= ~INT_RCV;
133
    }
134
    smc91c111_update(s);
135
}
136

    
137
/* Remove an item from the TX completion FIFO.  */
138
static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
139
{
140
    int i;
141

    
142
    if (s->tx_fifo_done_len == 0)
143
        return;
144
    s->tx_fifo_done_len--;
145
    for (i = 0; i < s->tx_fifo_done_len; i++)
146
        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
147
}
148

    
149
/* Release the memory allocated to a packet.  */
150
static void smc91c111_release_packet(smc91c111_state *s, int packet)
151
{
152
    s->allocated &= ~(1 << packet);
153
    if (s->tx_alloc == 0x80)
154
        smc91c111_tx_alloc(s);
155
}
156

    
157
/* Flush the TX FIFO.  */
158
static void smc91c111_do_tx(smc91c111_state *s)
159
{
160
    int i;
161
    int len;
162
    int control;
163
    int add_crc;
164
    int packetnum;
165
    uint8_t *p;
166

    
167
    if ((s->tcr & TCR_TXEN) == 0)
168
        return;
169
    if (s->tx_fifo_len == 0)
170
        return;
171
    for (i = 0; i < s->tx_fifo_len; i++) {
172
        packetnum = s->tx_fifo[i];
173
        p = &s->data[packetnum][0];
174
        /* Set status word.  */
175
        *(p++) = 0x01;
176
        *(p++) = 0x40;
177
        len = *(p++);
178
        len |= ((int)*(p++)) << 8;
179
        len -= 6;
180
        control = p[len + 1];
181
        if (control & 0x20)
182
            len++;
183
        /* ??? This overwrites the data following the buffer.
184
           Don't know what real hardware does.  */
185
        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
186
            memset(p + len, 0, 64 - len);
187
            len = 64;
188
        }
189
#if 0
190
        /* The card is supposed to append the CRC to the frame.  However
191
           none of the other network traffic has the CRC appended.
192
           Suspect this is low level ethernet detail we don't need to worry
193
           about.  */
194
        add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
195
        if (add_crc) {
196
            uint32_t crc;
197

198
            crc = crc32(~0, p, len);
199
            memcpy(p + len, &crc, 4);
200
            len += 4;
201
        }
202
#else
203
        add_crc = 0;
204
#endif
205
        if (s->ctr & CTR_AUTO_RELEASE)
206
            /* Race?  */
207
            smc91c111_release_packet(s, packetnum);
208
        else if (s->tx_fifo_done_len < NUM_PACKETS)
209
            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
210
        qemu_send_packet(s->vc, p, len);
211
    }
212
    s->tx_fifo_len = 0;
213
    smc91c111_update(s);
214
}
215

    
216
/* Add a packet to the TX FIFO.  */
217
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
218
{
219
    if (s->tx_fifo_len == NUM_PACKETS)
220
        return;
221
    s->tx_fifo[s->tx_fifo_len++] = packet;
222
    smc91c111_do_tx(s);
223
}
224

    
225
static void smc91c111_reset(smc91c111_state *s)
226
{
227
    s->bank = 0;
228
    s->tx_fifo_len = 0;
229
    s->tx_fifo_done_len = 0;
230
    s->rx_fifo_len = 0;
231
    s->allocated = 0;
232
    s->packet_num = 0;
233
    s->tx_alloc = 0;
234
    s->tcr = 0;
235
    s->rcr = 0;
236
    s->cr = 0xa0b1;
237
    s->ctr = 0x1210;
238
    s->ptr = 0;
239
    s->ercv = 0x1f;
240
    s->int_level = INT_TX_EMPTY;
241
    s->int_mask = 0;
242
    smc91c111_update(s);
243
}
244

    
245
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
246
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
247

    
248
static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
249
                             uint32_t value)
250
{
251
    smc91c111_state *s = (smc91c111_state *)opaque;
252

    
253
    if (offset == 14) {
254
        s->bank = value;
255
        return;
256
    }
257
    if (offset == 15)
258
        return;
259
    switch (s->bank) {
260
    case 0:
261
        switch (offset) {
262
        case 0: /* TCR */
263
            SET_LOW(tcr, value);
264
            return;
265
        case 1:
266
            SET_HIGH(tcr, value);
267
            return;
268
        case 4: /* RCR */
269
            SET_LOW(rcr, value);
270
            return;
271
        case 5:
272
            SET_HIGH(rcr, value);
273
            if (s->rcr & RCR_SOFT_RST)
274
                smc91c111_reset(s);
275
            return;
276
        case 10: case 11: /* RPCR */
277
            /* Ignored */
278
            return;
279
        }
280
        break;
281

    
282
    case 1:
283
        switch (offset) {
284
        case 0: /* CONFIG */
285
            SET_LOW(cr, value);
286
            return;
287
        case 1:
288
            SET_HIGH(cr,value);
289
            return;
290
        case 2: case 3: /* BASE */
291
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
292
            /* Not implemented.  */
293
            return;
294
        case 10: /* Genral Purpose */
295
            SET_LOW(gpr, value);
296
            return;
297
        case 11:
298
            SET_HIGH(gpr, value);
299
            return;
300
        case 12: /* Control */
301
            if (value & 1)
302
                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
303
            if (value & 2)
304
                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
305
            value &= ~3;
306
            SET_LOW(ctr, value);
307
            return;
308
        case 13:
309
            SET_HIGH(ctr, value);
310
            return;
311
        }
312
        break;
313

    
314
    case 2:
315
        switch (offset) {
316
        case 0: /* MMU Command */
317
            switch (value >> 5) {
318
            case 0: /* no-op */
319
                break;
320
            case 1: /* Allocate for TX.  */
321
                s->tx_alloc = 0x80;
322
                s->int_level &= ~INT_ALLOC;
323
                smc91c111_update(s);
324
                smc91c111_tx_alloc(s);
325
                break;
326
            case 2: /* Reset MMU.  */
327
                s->allocated = 0;
328
                s->tx_fifo_len = 0;
329
                s->tx_fifo_done_len = 0;
330
                s->rx_fifo_len = 0;
331
                s->tx_alloc = 0;
332
                break;
333
            case 3: /* Remove from RX FIFO.  */
334
                smc91c111_pop_rx_fifo(s);
335
                break;
336
            case 4: /* Remove from RX FIFO and release.  */
337
                if (s->rx_fifo_len > 0) {
338
                    smc91c111_release_packet(s, s->rx_fifo[0]);
339
                }
340
                smc91c111_pop_rx_fifo(s);
341
                break;
342
            case 5: /* Release.  */
343
                smc91c111_release_packet(s, s->packet_num);
344
                break;
345
            case 6: /* Add to TX FIFO.  */
346
                smc91c111_queue_tx(s, s->packet_num);
347
                break;
348
            case 7: /* Reset TX FIFO.  */
349
                s->tx_fifo_len = 0;
350
                s->tx_fifo_done_len = 0;
351
                break;
352
            }
353
            return;
354
        case 1:
355
            /* Ignore.  */
356
            return;
357
        case 2: /* Packet Number Register */
358
            s->packet_num = value;
359
            return;
360
        case 3: case 4: case 5:
361
            /* Should be readonly, but linux writes to them anyway. Ignore.  */
362
            return;
363
        case 6: /* Pointer */
364
            SET_LOW(ptr, value);
365
            return;
366
        case 7:
367
            SET_HIGH(ptr, value);
368
            return;
369
        case 8: case 9: case 10: case 11: /* Data */
370
            {
371
                int p;
372
                int n;
373

    
374
                if (s->ptr & 0x8000)
375
                    n = s->rx_fifo[0];
376
                else
377
                    n = s->packet_num;
378
                p = s->ptr & 0x07ff;
379
                if (s->ptr & 0x4000) {
380
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
381
                } else {
382
                    p += (offset & 3);
383
                }
384
                s->data[n][p] = value;
385
            }
386
            return;
387
        case 12: /* Interrupt ACK.  */
388
            s->int_level &= ~(value & 0xd6);
389
            if (value & INT_TX)
390
                smc91c111_pop_tx_fifo_done(s);
391
            smc91c111_update(s);
392
            return;
393
        case 13: /* Interrupt mask.  */
394
            s->int_mask = value;
395
            smc91c111_update(s);
396
            return;
397
        }
398
        break;;
399

    
400
    case 3:
401
        switch (offset) {
402
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
403
            /* Multicast table.  */
404
            /* Not implemented.  */
405
            return;
406
        case 8: case 9: /* Management Interface.  */
407
            /* Not implemented.  */
408
            return;
409
        case 12: /* Early receive.  */
410
            s->ercv = value & 0x1f;
411
        case 13:
412
            /* Ignore.  */
413
            return;
414
        }
415
        break;
416
    }
417
    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
418
}
419

    
420
static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
421
{
422
    smc91c111_state *s = (smc91c111_state *)opaque;
423

    
424
    if (offset == 14) {
425
        return s->bank;
426
    }
427
    if (offset == 15)
428
        return 0x33;
429
    switch (s->bank) {
430
    case 0:
431
        switch (offset) {
432
        case 0: /* TCR */
433
            return s->tcr & 0xff;
434
        case 1:
435
            return s->tcr >> 8;
436
        case 2: /* EPH Status */
437
            return 0;
438
        case 3:
439
            return 0x40;
440
        case 4: /* RCR */
441
            return s->rcr & 0xff;
442
        case 5:
443
            return s->rcr >> 8;
444
        case 6: /* Counter */
445
        case 7:
446
            /* Not implemented.  */
447
            return 0;
448
        case 8: /* Memory size.  */
449
            return NUM_PACKETS;
450
        case 9: /* Free memory available.  */
451
            {
452
                int i;
453
                int n;
454
                n = 0;
455
                for (i = 0; i < NUM_PACKETS; i++) {
456
                    if (s->allocated & (1 << i))
457
                        n++;
458
                }
459
                return n;
460
            }
461
        case 10: case 11: /* RPCR */
462
            /* Not implemented.  */
463
            return 0;
464
        }
465
        break;
466

    
467
    case 1:
468
        switch (offset) {
469
        case 0: /* CONFIG */
470
            return s->cr & 0xff;
471
        case 1:
472
            return s->cr >> 8;
473
        case 2: case 3: /* BASE */
474
            /* Not implemented.  */
475
            return 0;
476
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
477
            return s->conf.macaddr.a[offset - 4];
478
        case 10: /* General Purpose */
479
            return s->gpr & 0xff;
480
        case 11:
481
            return s->gpr >> 8;
482
        case 12: /* Control */
483
            return s->ctr & 0xff;
484
        case 13:
485
            return s->ctr >> 8;
486
        }
487
        break;
488

    
489
    case 2:
490
        switch (offset) {
491
        case 0: case 1: /* MMUCR Busy bit.  */
492
            return 0;
493
        case 2: /* Packet Number.  */
494
            return s->packet_num;
495
        case 3: /* Allocation Result.  */
496
            return s->tx_alloc;
497
        case 4: /* TX FIFO */
498
            if (s->tx_fifo_done_len == 0)
499
                return 0x80;
500
            else
501
                return s->tx_fifo_done[0];
502
        case 5: /* RX FIFO */
503
            if (s->rx_fifo_len == 0)
504
                return 0x80;
505
            else
506
                return s->rx_fifo[0];
507
        case 6: /* Pointer */
508
            return s->ptr & 0xff;
509
        case 7:
510
            return (s->ptr >> 8) & 0xf7;
511
        case 8: case 9: case 10: case 11: /* Data */
512
            {
513
                int p;
514
                int n;
515

    
516
                if (s->ptr & 0x8000)
517
                    n = s->rx_fifo[0];
518
                else
519
                    n = s->packet_num;
520
                p = s->ptr & 0x07ff;
521
                if (s->ptr & 0x4000) {
522
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
523
                } else {
524
                    p += (offset & 3);
525
                }
526
                return s->data[n][p];
527
            }
528
        case 12: /* Interrupt status.  */
529
            return s->int_level;
530
        case 13: /* Interrupt mask.  */
531
            return s->int_mask;
532
        }
533
        break;
534

    
535
    case 3:
536
        switch (offset) {
537
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
538
            /* Multicast table.  */
539
            /* Not implemented.  */
540
            return 0;
541
        case 8: /* Management Interface.  */
542
            /* Not implemented.  */
543
            return 0x30;
544
        case 9:
545
            return 0x33;
546
        case 10: /* Revision.  */
547
            return 0x91;
548
        case 11:
549
            return 0x33;
550
        case 12:
551
            return s->ercv;
552
        case 13:
553
            return 0;
554
        }
555
        break;
556
    }
557
    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
558
    return 0;
559
}
560

    
561
static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
562
                             uint32_t value)
563
{
564
    smc91c111_writeb(opaque, offset, value & 0xff);
565
    smc91c111_writeb(opaque, offset + 1, value >> 8);
566
}
567

    
568
static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
569
                             uint32_t value)
570
{
571
    /* 32-bit writes to offset 0xc only actually write to the bank select
572
       register (offset 0xe)  */
573
    if (offset != 0xc)
574
        smc91c111_writew(opaque, offset, value & 0xffff);
575
    smc91c111_writew(opaque, offset + 2, value >> 16);
576
}
577

    
578
static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
579
{
580
    uint32_t val;
581
    val = smc91c111_readb(opaque, offset);
582
    val |= smc91c111_readb(opaque, offset + 1) << 8;
583
    return val;
584
}
585

    
586
static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
587
{
588
    uint32_t val;
589
    val = smc91c111_readw(opaque, offset);
590
    val |= smc91c111_readw(opaque, offset + 2) << 16;
591
    return val;
592
}
593

    
594
static int smc91c111_can_receive(VLANClientState *vc)
595
{
596
    smc91c111_state *s = vc->opaque;
597

    
598
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
599
        return 1;
600
    if (s->allocated == (1 << NUM_PACKETS) - 1)
601
        return 0;
602
    return 1;
603
}
604

    
605
static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
606
{
607
    smc91c111_state *s = vc->opaque;
608
    int status;
609
    int packetsize;
610
    uint32_t crc;
611
    int packetnum;
612
    uint8_t *p;
613

    
614
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
615
        return -1;
616
    /* Short packets are padded with zeros.  Receiving a packet
617
       < 64 bytes long is considered an error condition.  */
618
    if (size < 64)
619
        packetsize = 64;
620
    else
621
        packetsize = (size & ~1);
622
    packetsize += 6;
623
    crc = (s->rcr & RCR_STRIP_CRC) == 0;
624
    if (crc)
625
        packetsize += 4;
626
    /* TODO: Flag overrun and receive errors.  */
627
    if (packetsize > 2048)
628
        return -1;
629
    packetnum = smc91c111_allocate_packet(s);
630
    if (packetnum == 0x80)
631
        return -1;
632
    s->rx_fifo[s->rx_fifo_len++] = packetnum;
633

    
634
    p = &s->data[packetnum][0];
635
    /* ??? Multicast packets?  */
636
    status = 0;
637
    if (size > 1518)
638
        status |= RS_TOOLONG;
639
    if (size & 1)
640
        status |= RS_ODDFRAME;
641
    *(p++) = status & 0xff;
642
    *(p++) = status >> 8;
643
    *(p++) = packetsize & 0xff;
644
    *(p++) = packetsize >> 8;
645
    memcpy(p, buf, size & ~1);
646
    p += (size & ~1);
647
    /* Pad short packets.  */
648
    if (size < 64) {
649
        int pad;
650

    
651
        if (size & 1)
652
            *(p++) = buf[size - 1];
653
        pad = 64 - size;
654
        memset(p, 0, pad);
655
        p += pad;
656
        size = 64;
657
    }
658
    /* It's not clear if the CRC should go before or after the last byte in
659
       odd sized packets.  Linux disables the CRC, so that's no help.
660
       The pictures in the documentation show the CRC aligned on a 16-bit
661
       boundary before the last odd byte, so that's what we do.  */
662
    if (crc) {
663
        crc = crc32(~0, buf, size);
664
        *(p++) = crc & 0xff; crc >>= 8;
665
        *(p++) = crc & 0xff; crc >>= 8;
666
        *(p++) = crc & 0xff; crc >>= 8;
667
        *(p++) = crc & 0xff; crc >>= 8;
668
    }
669
    if (size & 1) {
670
        *(p++) = buf[size - 1];
671
        *(p++) = 0x60;
672
    } else {
673
        *(p++) = 0;
674
        *(p++) = 0x40;
675
    }
676
    /* TODO: Raise early RX interrupt?  */
677
    s->int_level |= INT_RCV;
678
    smc91c111_update(s);
679

    
680
    return size;
681
}
682

    
683
static CPUReadMemoryFunc * const smc91c111_readfn[] = {
684
    smc91c111_readb,
685
    smc91c111_readw,
686
    smc91c111_readl
687
};
688

    
689
static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
690
    smc91c111_writeb,
691
    smc91c111_writew,
692
    smc91c111_writel
693
};
694

    
695
static void smc91c111_cleanup(VLANClientState *vc)
696
{
697
    smc91c111_state *s = vc->opaque;
698

    
699
    s->vc = NULL;
700
}
701

    
702
static int smc91c111_init1(SysBusDevice *dev)
703
{
704
    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
705

    
706
    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
707
                                           smc91c111_writefn, s);
708
    sysbus_init_mmio(dev, 16, s->mmio_index);
709
    sysbus_init_irq(dev, &s->irq);
710
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
711

    
712
    smc91c111_reset(s);
713

    
714
    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
715
                                 s->conf.vlan, s->conf.peer,
716
                                 dev->qdev.info->name, dev->qdev.id,
717
                                 smc91c111_can_receive, smc91c111_receive, NULL,
718
                                 NULL, smc91c111_cleanup, s);
719
    qemu_format_nic_info_str(s->vc, s->conf.macaddr.a);
720
    /* ??? Save/restore.  */
721
    return 0;
722
}
723

    
724
static SysBusDeviceInfo smc91c111_info = {
725
    .init = smc91c111_init1,
726
    .qdev.name  = "smc91c111",
727
    .qdev.size  = sizeof(smc91c111_state),
728
    .qdev.props = (Property[]) {
729
        DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
730
        DEFINE_PROP_END_OF_LIST(),
731
    }
732
};
733

    
734
static void smc91c111_register_devices(void)
735
{
736
    sysbus_register_withprop(&smc91c111_info);
737
}
738

    
739
/* Legacy helper function.  Should go away when machine config files are
740
   implemented.  */
741
void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
742
{
743
    DeviceState *dev;
744
    SysBusDevice *s;
745

    
746
    qemu_check_nic_model(nd, "smc91c111");
747
    dev = qdev_create(NULL, "smc91c111");
748
    qdev_set_nic_properties(dev, nd);
749
    qdev_init_nofail(dev);
750
    s = sysbus_from_qdev(dev);
751
    sysbus_mmio_map(s, 0, base);
752
    sysbus_connect_irq(s, 0, irq);
753
}
754

    
755
device_init(smc91c111_register_devices)