Statistics
| Branch: | Revision:

root / hw / smc91c111.c @ c6df7102

History | View | Annotate | Download (21.6 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
    NICState *nic;
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
static const VMStateDescription vmstate_smc91c111 = {
50
    .name = "smc91c111",
51
    .version_id = 1,
52
    .minimum_version_id = 1,
53
    .fields      = (VMStateField []) {
54
        VMSTATE_UINT16(tcr, smc91c111_state),
55
        VMSTATE_UINT16(rcr, smc91c111_state),
56
        VMSTATE_UINT16(cr, smc91c111_state),
57
        VMSTATE_UINT16(ctr, smc91c111_state),
58
        VMSTATE_UINT16(gpr, smc91c111_state),
59
        VMSTATE_UINT16(ptr, smc91c111_state),
60
        VMSTATE_UINT16(ercv, smc91c111_state),
61
        VMSTATE_INT32(bank, smc91c111_state),
62
        VMSTATE_INT32(packet_num, smc91c111_state),
63
        VMSTATE_INT32(tx_alloc, smc91c111_state),
64
        VMSTATE_INT32(allocated, smc91c111_state),
65
        VMSTATE_INT32(tx_fifo_len, smc91c111_state),
66
        VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
67
        VMSTATE_INT32(rx_fifo_len, smc91c111_state),
68
        VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
69
        VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
70
        VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
71
        VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
72
        VMSTATE_UINT8(int_level, smc91c111_state),
73
        VMSTATE_UINT8(int_mask, smc91c111_state),
74
        VMSTATE_END_OF_LIST()
75
    }
76
};
77

    
78
#define RCR_SOFT_RST  0x8000
79
#define RCR_STRIP_CRC 0x0200
80
#define RCR_RXEN      0x0100
81

    
82
#define TCR_EPH_LOOP  0x2000
83
#define TCR_NOCRC     0x0100
84
#define TCR_PAD_EN    0x0080
85
#define TCR_FORCOL    0x0004
86
#define TCR_LOOP      0x0002
87
#define TCR_TXEN      0x0001
88

    
89
#define INT_MD        0x80
90
#define INT_ERCV      0x40
91
#define INT_EPH       0x20
92
#define INT_RX_OVRN   0x10
93
#define INT_ALLOC     0x08
94
#define INT_TX_EMPTY  0x04
95
#define INT_TX        0x02
96
#define INT_RCV       0x01
97

    
98
#define CTR_AUTO_RELEASE  0x0800
99
#define CTR_RELOAD        0x0002
100
#define CTR_STORE         0x0001
101

    
102
#define RS_ALGNERR      0x8000
103
#define RS_BRODCAST     0x4000
104
#define RS_BADCRC       0x2000
105
#define RS_ODDFRAME     0x1000
106
#define RS_TOOLONG      0x0800
107
#define RS_TOOSHORT     0x0400
108
#define RS_MULTICAST    0x0001
109

    
110
/* Update interrupt status.  */
111
static void smc91c111_update(smc91c111_state *s)
112
{
113
    int level;
114

    
115
    if (s->tx_fifo_len == 0)
116
        s->int_level |= INT_TX_EMPTY;
117
    if (s->tx_fifo_done_len != 0)
118
        s->int_level |= INT_TX;
119
    level = (s->int_level & s->int_mask) != 0;
120
    qemu_set_irq(s->irq, level);
121
}
122

    
123
/* Try to allocate a packet.  Returns 0x80 on failure.  */
124
static int smc91c111_allocate_packet(smc91c111_state *s)
125
{
126
    int i;
127
    if (s->allocated == (1 << NUM_PACKETS) - 1) {
128
        return 0x80;
129
    }
130

    
131
    for (i = 0; i < NUM_PACKETS; i++) {
132
        if ((s->allocated & (1 << i)) == 0)
133
            break;
134
    }
135
    s->allocated |= 1 << i;
136
    return i;
137
}
138

    
139

    
140
/* Process a pending TX allocate.  */
141
static void smc91c111_tx_alloc(smc91c111_state *s)
142
{
143
    s->tx_alloc = smc91c111_allocate_packet(s);
144
    if (s->tx_alloc == 0x80)
145
        return;
146
    s->int_level |= INT_ALLOC;
147
    smc91c111_update(s);
148
}
149

    
150
/* Remove and item from the RX FIFO.  */
151
static void smc91c111_pop_rx_fifo(smc91c111_state *s)
152
{
153
    int i;
154

    
155
    s->rx_fifo_len--;
156
    if (s->rx_fifo_len) {
157
        for (i = 0; i < s->rx_fifo_len; i++)
158
            s->rx_fifo[i] = s->rx_fifo[i + 1];
159
        s->int_level |= INT_RCV;
160
    } else {
161
        s->int_level &= ~INT_RCV;
162
    }
163
    smc91c111_update(s);
164
}
165

    
166
/* Remove an item from the TX completion FIFO.  */
167
static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
168
{
169
    int i;
170

    
171
    if (s->tx_fifo_done_len == 0)
172
        return;
173
    s->tx_fifo_done_len--;
174
    for (i = 0; i < s->tx_fifo_done_len; i++)
175
        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
176
}
177

    
178
/* Release the memory allocated to a packet.  */
179
static void smc91c111_release_packet(smc91c111_state *s, int packet)
180
{
181
    s->allocated &= ~(1 << packet);
182
    if (s->tx_alloc == 0x80)
183
        smc91c111_tx_alloc(s);
184
}
185

    
186
/* Flush the TX FIFO.  */
187
static void smc91c111_do_tx(smc91c111_state *s)
188
{
189
    int i;
190
    int len;
191
    int control;
192
    int packetnum;
193
    uint8_t *p;
194

    
195
    if ((s->tcr & TCR_TXEN) == 0)
196
        return;
197
    if (s->tx_fifo_len == 0)
198
        return;
199
    for (i = 0; i < s->tx_fifo_len; i++) {
200
        packetnum = s->tx_fifo[i];
201
        p = &s->data[packetnum][0];
202
        /* Set status word.  */
203
        *(p++) = 0x01;
204
        *(p++) = 0x40;
205
        len = *(p++);
206
        len |= ((int)*(p++)) << 8;
207
        len -= 6;
208
        control = p[len + 1];
209
        if (control & 0x20)
210
            len++;
211
        /* ??? This overwrites the data following the buffer.
212
           Don't know what real hardware does.  */
213
        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
214
            memset(p + len, 0, 64 - len);
215
            len = 64;
216
        }
217
#if 0
218
        {
219
            int add_crc;
220

221
            /* The card is supposed to append the CRC to the frame.
222
               However none of the other network traffic has the CRC
223
               appended.  Suspect this is low level ethernet detail we
224
               don't need to worry about.  */
225
            add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
226
            if (add_crc) {
227
                uint32_t crc;
228

229
                crc = crc32(~0, p, len);
230
                memcpy(p + len, &crc, 4);
231
                len += 4;
232
            }
233
        }
234
#endif
235
        if (s->ctr & CTR_AUTO_RELEASE)
236
            /* Race?  */
237
            smc91c111_release_packet(s, packetnum);
238
        else if (s->tx_fifo_done_len < NUM_PACKETS)
239
            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
240
        qemu_send_packet(&s->nic->nc, p, len);
241
    }
242
    s->tx_fifo_len = 0;
243
    smc91c111_update(s);
244
}
245

    
246
/* Add a packet to the TX FIFO.  */
247
static void smc91c111_queue_tx(smc91c111_state *s, int packet)
248
{
249
    if (s->tx_fifo_len == NUM_PACKETS)
250
        return;
251
    s->tx_fifo[s->tx_fifo_len++] = packet;
252
    smc91c111_do_tx(s);
253
}
254

    
255
static void smc91c111_reset(smc91c111_state *s)
256
{
257
    s->bank = 0;
258
    s->tx_fifo_len = 0;
259
    s->tx_fifo_done_len = 0;
260
    s->rx_fifo_len = 0;
261
    s->allocated = 0;
262
    s->packet_num = 0;
263
    s->tx_alloc = 0;
264
    s->tcr = 0;
265
    s->rcr = 0;
266
    s->cr = 0xa0b1;
267
    s->ctr = 0x1210;
268
    s->ptr = 0;
269
    s->ercv = 0x1f;
270
    s->int_level = INT_TX_EMPTY;
271
    s->int_mask = 0;
272
    smc91c111_update(s);
273
}
274

    
275
#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
276
#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
277

    
278
static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
279
                             uint32_t value)
280
{
281
    smc91c111_state *s = (smc91c111_state *)opaque;
282

    
283
    offset = offset & 0xf;
284
    if (offset == 14) {
285
        s->bank = value;
286
        return;
287
    }
288
    if (offset == 15)
289
        return;
290
    switch (s->bank) {
291
    case 0:
292
        switch (offset) {
293
        case 0: /* TCR */
294
            SET_LOW(tcr, value);
295
            return;
296
        case 1:
297
            SET_HIGH(tcr, value);
298
            return;
299
        case 4: /* RCR */
300
            SET_LOW(rcr, value);
301
            return;
302
        case 5:
303
            SET_HIGH(rcr, value);
304
            if (s->rcr & RCR_SOFT_RST)
305
                smc91c111_reset(s);
306
            return;
307
        case 10: case 11: /* RPCR */
308
            /* Ignored */
309
            return;
310
        case 12: case 13: /* Reserved */
311
            return;
312
        }
313
        break;
314

    
315
    case 1:
316
        switch (offset) {
317
        case 0: /* CONFIG */
318
            SET_LOW(cr, value);
319
            return;
320
        case 1:
321
            SET_HIGH(cr,value);
322
            return;
323
        case 2: case 3: /* BASE */
324
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
325
            /* Not implemented.  */
326
            return;
327
        case 10: /* Genral Purpose */
328
            SET_LOW(gpr, value);
329
            return;
330
        case 11:
331
            SET_HIGH(gpr, value);
332
            return;
333
        case 12: /* Control */
334
            if (value & 1)
335
                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
336
            if (value & 2)
337
                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
338
            value &= ~3;
339
            SET_LOW(ctr, value);
340
            return;
341
        case 13:
342
            SET_HIGH(ctr, value);
343
            return;
344
        }
345
        break;
346

    
347
    case 2:
348
        switch (offset) {
349
        case 0: /* MMU Command */
350
            switch (value >> 5) {
351
            case 0: /* no-op */
352
                break;
353
            case 1: /* Allocate for TX.  */
354
                s->tx_alloc = 0x80;
355
                s->int_level &= ~INT_ALLOC;
356
                smc91c111_update(s);
357
                smc91c111_tx_alloc(s);
358
                break;
359
            case 2: /* Reset MMU.  */
360
                s->allocated = 0;
361
                s->tx_fifo_len = 0;
362
                s->tx_fifo_done_len = 0;
363
                s->rx_fifo_len = 0;
364
                s->tx_alloc = 0;
365
                break;
366
            case 3: /* Remove from RX FIFO.  */
367
                smc91c111_pop_rx_fifo(s);
368
                break;
369
            case 4: /* Remove from RX FIFO and release.  */
370
                if (s->rx_fifo_len > 0) {
371
                    smc91c111_release_packet(s, s->rx_fifo[0]);
372
                }
373
                smc91c111_pop_rx_fifo(s);
374
                break;
375
            case 5: /* Release.  */
376
                smc91c111_release_packet(s, s->packet_num);
377
                break;
378
            case 6: /* Add to TX FIFO.  */
379
                smc91c111_queue_tx(s, s->packet_num);
380
                break;
381
            case 7: /* Reset TX FIFO.  */
382
                s->tx_fifo_len = 0;
383
                s->tx_fifo_done_len = 0;
384
                break;
385
            }
386
            return;
387
        case 1:
388
            /* Ignore.  */
389
            return;
390
        case 2: /* Packet Number Register */
391
            s->packet_num = value;
392
            return;
393
        case 3: case 4: case 5:
394
            /* Should be readonly, but linux writes to them anyway. Ignore.  */
395
            return;
396
        case 6: /* Pointer */
397
            SET_LOW(ptr, value);
398
            return;
399
        case 7:
400
            SET_HIGH(ptr, value);
401
            return;
402
        case 8: case 9: case 10: case 11: /* Data */
403
            {
404
                int p;
405
                int n;
406

    
407
                if (s->ptr & 0x8000)
408
                    n = s->rx_fifo[0];
409
                else
410
                    n = s->packet_num;
411
                p = s->ptr & 0x07ff;
412
                if (s->ptr & 0x4000) {
413
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
414
                } else {
415
                    p += (offset & 3);
416
                }
417
                s->data[n][p] = value;
418
            }
419
            return;
420
        case 12: /* Interrupt ACK.  */
421
            s->int_level &= ~(value & 0xd6);
422
            if (value & INT_TX)
423
                smc91c111_pop_tx_fifo_done(s);
424
            smc91c111_update(s);
425
            return;
426
        case 13: /* Interrupt mask.  */
427
            s->int_mask = value;
428
            smc91c111_update(s);
429
            return;
430
        }
431
        break;;
432

    
433
    case 3:
434
        switch (offset) {
435
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
436
            /* Multicast table.  */
437
            /* Not implemented.  */
438
            return;
439
        case 8: case 9: /* Management Interface.  */
440
            /* Not implemented.  */
441
            return;
442
        case 12: /* Early receive.  */
443
            s->ercv = value & 0x1f;
444
        case 13:
445
            /* Ignore.  */
446
            return;
447
        }
448
        break;
449
    }
450
    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
451
}
452

    
453
static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
454
{
455
    smc91c111_state *s = (smc91c111_state *)opaque;
456

    
457
    offset = offset & 0xf;
458
    if (offset == 14) {
459
        return s->bank;
460
    }
461
    if (offset == 15)
462
        return 0x33;
463
    switch (s->bank) {
464
    case 0:
465
        switch (offset) {
466
        case 0: /* TCR */
467
            return s->tcr & 0xff;
468
        case 1:
469
            return s->tcr >> 8;
470
        case 2: /* EPH Status */
471
            return 0;
472
        case 3:
473
            return 0x40;
474
        case 4: /* RCR */
475
            return s->rcr & 0xff;
476
        case 5:
477
            return s->rcr >> 8;
478
        case 6: /* Counter */
479
        case 7:
480
            /* Not implemented.  */
481
            return 0;
482
        case 8: /* Memory size.  */
483
            return NUM_PACKETS;
484
        case 9: /* Free memory available.  */
485
            {
486
                int i;
487
                int n;
488
                n = 0;
489
                for (i = 0; i < NUM_PACKETS; i++) {
490
                    if (s->allocated & (1 << i))
491
                        n++;
492
                }
493
                return n;
494
            }
495
        case 10: case 11: /* RPCR */
496
            /* Not implemented.  */
497
            return 0;
498
        case 12: case 13: /* Reserved */
499
            return 0;
500
        }
501
        break;
502

    
503
    case 1:
504
        switch (offset) {
505
        case 0: /* CONFIG */
506
            return s->cr & 0xff;
507
        case 1:
508
            return s->cr >> 8;
509
        case 2: case 3: /* BASE */
510
            /* Not implemented.  */
511
            return 0;
512
        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
513
            return s->conf.macaddr.a[offset - 4];
514
        case 10: /* General Purpose */
515
            return s->gpr & 0xff;
516
        case 11:
517
            return s->gpr >> 8;
518
        case 12: /* Control */
519
            return s->ctr & 0xff;
520
        case 13:
521
            return s->ctr >> 8;
522
        }
523
        break;
524

    
525
    case 2:
526
        switch (offset) {
527
        case 0: case 1: /* MMUCR Busy bit.  */
528
            return 0;
529
        case 2: /* Packet Number.  */
530
            return s->packet_num;
531
        case 3: /* Allocation Result.  */
532
            return s->tx_alloc;
533
        case 4: /* TX FIFO */
534
            if (s->tx_fifo_done_len == 0)
535
                return 0x80;
536
            else
537
                return s->tx_fifo_done[0];
538
        case 5: /* RX FIFO */
539
            if (s->rx_fifo_len == 0)
540
                return 0x80;
541
            else
542
                return s->rx_fifo[0];
543
        case 6: /* Pointer */
544
            return s->ptr & 0xff;
545
        case 7:
546
            return (s->ptr >> 8) & 0xf7;
547
        case 8: case 9: case 10: case 11: /* Data */
548
            {
549
                int p;
550
                int n;
551

    
552
                if (s->ptr & 0x8000)
553
                    n = s->rx_fifo[0];
554
                else
555
                    n = s->packet_num;
556
                p = s->ptr & 0x07ff;
557
                if (s->ptr & 0x4000) {
558
                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
559
                } else {
560
                    p += (offset & 3);
561
                }
562
                return s->data[n][p];
563
            }
564
        case 12: /* Interrupt status.  */
565
            return s->int_level;
566
        case 13: /* Interrupt mask.  */
567
            return s->int_mask;
568
        }
569
        break;
570

    
571
    case 3:
572
        switch (offset) {
573
        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
574
            /* Multicast table.  */
575
            /* Not implemented.  */
576
            return 0;
577
        case 8: /* Management Interface.  */
578
            /* Not implemented.  */
579
            return 0x30;
580
        case 9:
581
            return 0x33;
582
        case 10: /* Revision.  */
583
            return 0x91;
584
        case 11:
585
            return 0x33;
586
        case 12:
587
            return s->ercv;
588
        case 13:
589
            return 0;
590
        }
591
        break;
592
    }
593
    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
594
    return 0;
595
}
596

    
597
static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
598
                             uint32_t value)
599
{
600
    smc91c111_writeb(opaque, offset, value & 0xff);
601
    smc91c111_writeb(opaque, offset + 1, value >> 8);
602
}
603

    
604
static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
605
                             uint32_t value)
606
{
607
    /* 32-bit writes to offset 0xc only actually write to the bank select
608
       register (offset 0xe)  */
609
    if (offset != 0xc)
610
        smc91c111_writew(opaque, offset, value & 0xffff);
611
    smc91c111_writew(opaque, offset + 2, value >> 16);
612
}
613

    
614
static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
615
{
616
    uint32_t val;
617
    val = smc91c111_readb(opaque, offset);
618
    val |= smc91c111_readb(opaque, offset + 1) << 8;
619
    return val;
620
}
621

    
622
static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
623
{
624
    uint32_t val;
625
    val = smc91c111_readw(opaque, offset);
626
    val |= smc91c111_readw(opaque, offset + 2) << 16;
627
    return val;
628
}
629

    
630
static int smc91c111_can_receive(VLANClientState *nc)
631
{
632
    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
633

    
634
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
635
        return 1;
636
    if (s->allocated == (1 << NUM_PACKETS) - 1)
637
        return 0;
638
    return 1;
639
}
640

    
641
static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
642
{
643
    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
644
    int status;
645
    int packetsize;
646
    uint32_t crc;
647
    int packetnum;
648
    uint8_t *p;
649

    
650
    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
651
        return -1;
652
    /* Short packets are padded with zeros.  Receiving a packet
653
       < 64 bytes long is considered an error condition.  */
654
    if (size < 64)
655
        packetsize = 64;
656
    else
657
        packetsize = (size & ~1);
658
    packetsize += 6;
659
    crc = (s->rcr & RCR_STRIP_CRC) == 0;
660
    if (crc)
661
        packetsize += 4;
662
    /* TODO: Flag overrun and receive errors.  */
663
    if (packetsize > 2048)
664
        return -1;
665
    packetnum = smc91c111_allocate_packet(s);
666
    if (packetnum == 0x80)
667
        return -1;
668
    s->rx_fifo[s->rx_fifo_len++] = packetnum;
669

    
670
    p = &s->data[packetnum][0];
671
    /* ??? Multicast packets?  */
672
    status = 0;
673
    if (size > 1518)
674
        status |= RS_TOOLONG;
675
    if (size & 1)
676
        status |= RS_ODDFRAME;
677
    *(p++) = status & 0xff;
678
    *(p++) = status >> 8;
679
    *(p++) = packetsize & 0xff;
680
    *(p++) = packetsize >> 8;
681
    memcpy(p, buf, size & ~1);
682
    p += (size & ~1);
683
    /* Pad short packets.  */
684
    if (size < 64) {
685
        int pad;
686

    
687
        if (size & 1)
688
            *(p++) = buf[size - 1];
689
        pad = 64 - size;
690
        memset(p, 0, pad);
691
        p += pad;
692
        size = 64;
693
    }
694
    /* It's not clear if the CRC should go before or after the last byte in
695
       odd sized packets.  Linux disables the CRC, so that's no help.
696
       The pictures in the documentation show the CRC aligned on a 16-bit
697
       boundary before the last odd byte, so that's what we do.  */
698
    if (crc) {
699
        crc = crc32(~0, buf, size);
700
        *(p++) = crc & 0xff; crc >>= 8;
701
        *(p++) = crc & 0xff; crc >>= 8;
702
        *(p++) = crc & 0xff; crc >>= 8;
703
        *(p++) = crc & 0xff;
704
    }
705
    if (size & 1) {
706
        *(p++) = buf[size - 1];
707
        *p = 0x60;
708
    } else {
709
        *(p++) = 0;
710
        *p = 0x40;
711
    }
712
    /* TODO: Raise early RX interrupt?  */
713
    s->int_level |= INT_RCV;
714
    smc91c111_update(s);
715

    
716
    return size;
717
}
718

    
719
static CPUReadMemoryFunc * const smc91c111_readfn[] = {
720
    smc91c111_readb,
721
    smc91c111_readw,
722
    smc91c111_readl
723
};
724

    
725
static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
726
    smc91c111_writeb,
727
    smc91c111_writew,
728
    smc91c111_writel
729
};
730

    
731
static void smc91c111_cleanup(VLANClientState *nc)
732
{
733
    smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
734

    
735
    s->nic = NULL;
736
}
737

    
738
static NetClientInfo net_smc91c111_info = {
739
    .type = NET_CLIENT_TYPE_NIC,
740
    .size = sizeof(NICState),
741
    .can_receive = smc91c111_can_receive,
742
    .receive = smc91c111_receive,
743
    .cleanup = smc91c111_cleanup,
744
};
745

    
746
static int smc91c111_init1(SysBusDevice *dev)
747
{
748
    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
749

    
750
    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
751
                                           smc91c111_writefn, s,
752
                                           DEVICE_NATIVE_ENDIAN);
753
    sysbus_init_mmio(dev, 16, s->mmio_index);
754
    sysbus_init_irq(dev, &s->irq);
755
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
756

    
757
    smc91c111_reset(s);
758

    
759
    s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
760
                          dev->qdev.info->name, dev->qdev.id, s);
761
    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
762
    /* ??? Save/restore.  */
763
    return 0;
764
}
765

    
766
static SysBusDeviceInfo smc91c111_info = {
767
    .init = smc91c111_init1,
768
    .qdev.name  = "smc91c111",
769
    .qdev.size  = sizeof(smc91c111_state),
770
    .qdev.vmsd = &vmstate_smc91c111,
771
    .qdev.props = (Property[]) {
772
        DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
773
        DEFINE_PROP_END_OF_LIST(),
774
    }
775
};
776

    
777
static void smc91c111_register_devices(void)
778
{
779
    sysbus_register_withprop(&smc91c111_info);
780
}
781

    
782
/* Legacy helper function.  Should go away when machine config files are
783
   implemented.  */
784
void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
785
{
786
    DeviceState *dev;
787
    SysBusDevice *s;
788

    
789
    qemu_check_nic_model(nd, "smc91c111");
790
    dev = qdev_create(NULL, "smc91c111");
791
    qdev_set_nic_properties(dev, nd);
792
    qdev_init_nofail(dev);
793
    s = sysbus_from_qdev(dev);
794
    sysbus_mmio_map(s, 0, base);
795
    sysbus_connect_irq(s, 0, irq);
796
}
797

    
798
device_init(smc91c111_register_devices)