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 "hw/sysbus.h"
11#include "net/net.h"
12#include "hw/devices.h"
13#include "hw/hw.h"
14/* For crc32 */
15#include <zlib.h>
16
17/* Number of 2k memory pages available.  */
18#define NUM_PACKETS 4
19#define BUFFER_PER_PACKET 2048
20
21typedef struct {
22    SysBusDevice busdev;
23    VLANClientState *vc;
24    uint16_t tcr;
25    uint16_t rcr;
26    uint16_t cr;
27    uint16_t ctr;
28    uint16_t gpr;
29    uint16_t ptr;
30    uint16_t ercv;
31    qemu_irq irq;
32    int bank;
33    int packet_num;
34    int tx_alloc;
35    /* Bitmask of allocated packets.  */
36    int allocated;
37    int tx_fifo_len;
38    int tx_fifo[NUM_PACKETS];
39    int rx_fifo_len;
40    int rx_fifo[NUM_PACKETS];
41    int tx_fifo_done_len;
42    int tx_fifo_done[NUM_PACKETS];
43    /* Packet buffer memory.  */
44    uint8_t data[NUM_PACKETS][BUFFER_PER_PACKET];
45    uint8_t int_level;
46    uint8_t int_mask;
47    uint8_t macaddr[6];
48    int mmio_index;
49} smc91c111_state;
50
51#define SMC91C111_SAVE_VERSION 1
52
53static void smc91c111_save(QEMUFile *f, void *opaque)
54{
55    smc91c111_state *s = opaque;
56
57    /* busdev, vc, macaddr and mmio_index are linked to the host state and
58     * initialized when the emulator starts (in smc91c111_init1 below).
59     * Saving/restoring those values is therefore useless and may even be
60     * harmful, so they are omitted.
61     */
62    qemu_put_be16(f, s->tcr);
63    qemu_put_be16(f, s->rcr);
64    qemu_put_be16(f, s->cr);
65    qemu_put_be16(f, s->ctr);
66    qemu_put_be16(f, s->gpr);
67    qemu_put_be16(f, s->ptr);
68    qemu_put_be16(f, s->ercv);
69
70    qemu_put_be32(f, s->bank);
71    qemu_put_be32(f, s->packet_num);
72
73    qemu_put_be32(f, s->tx_alloc);
74    qemu_put_be32(f, s->allocated);
75    qemu_put_be32(f, s->tx_fifo_len);
76    qemu_put_buffer(f, (uint8_t*) s->tx_fifo, sizeof(s->tx_fifo));
77    qemu_put_be32(f, s->rx_fifo_len);
78    qemu_put_buffer(f, (uint8_t*) s->rx_fifo, sizeof(s->rx_fifo));
79    qemu_put_be32(f, s->tx_fifo_done_len);
80    qemu_put_buffer(f, (uint8_t*) s->tx_fifo_done, sizeof(s->tx_fifo_done));
81
82    /* Packet buffer memory.  */
83    qemu_put_buffer(f, (uint8_t*) s->data, sizeof(s->data));
84    qemu_put_byte(f, s->int_level);
85    qemu_put_byte(f, s->int_mask);
86
87    /* macaddr, mmio_index omitted intentionally */
88}
89
90static int smc91c111_load(QEMUFile *f, void *opaque, int version_id)
91{
92    smc91c111_state *s = opaque;
93
94    if (version_id != SMC91C111_SAVE_VERSION) {
95        return -1;
96    }
97
98    s->tcr = qemu_get_be16(f);
99    s->rcr = qemu_get_be16(f);
100    s->cr = qemu_get_be16(f);
101    s->ctr = qemu_get_be16(f);
102    s->gpr = qemu_get_be16(f);
103    s->ptr = qemu_get_be16(f);
104    s->ercv = qemu_get_be16(f);
105
106    s->bank = qemu_get_be32(f);
107    s->packet_num = qemu_get_be32(f);
108
109    s->tx_alloc = qemu_get_be32(f);
110    s->allocated = qemu_get_be32(f);
111    s->tx_fifo_len = qemu_get_be32(f);
112    qemu_get_buffer(f, (uint8_t*) s->tx_fifo, sizeof(s->tx_fifo));
113    s->rx_fifo_len = qemu_get_be32(f);
114    qemu_get_buffer(f, (uint8_t*) s->rx_fifo, sizeof(s->rx_fifo));
115    s->tx_fifo_done_len = qemu_get_be32(f);
116    qemu_get_buffer(f, (uint8_t*) s->tx_fifo_done, sizeof(s->tx_fifo_done));
117
118    /* Packet buffer memory.  */
119    qemu_get_buffer(f, (uint8_t*) s->data, sizeof(s->data));
120    s->int_level = qemu_get_byte(f);
121    s->int_mask = qemu_get_byte(f);
122
123    return 0;
124}
125
126#define RCR_SOFT_RST  0x8000
127#define RCR_STRIP_CRC 0x0200
128#define RCR_RXEN      0x0100
129
130#define TCR_EPH_LOOP  0x2000
131#define TCR_NOCRC     0x0100
132#define TCR_PAD_EN    0x0080
133#define TCR_FORCOL    0x0004
134#define TCR_LOOP      0x0002
135#define TCR_TXEN      0x0001
136
137#define INT_MD        0x80
138#define INT_ERCV      0x40
139#define INT_EPH       0x20
140#define INT_RX_OVRN   0x10
141#define INT_ALLOC     0x08
142#define INT_TX_EMPTY  0x04
143#define INT_TX        0x02
144#define INT_RCV       0x01
145
146#define CTR_AUTO_RELEASE  0x0800
147#define CTR_RELOAD        0x0002
148#define CTR_STORE         0x0001
149
150#define RS_ALGNERR      0x8000
151#define RS_BRODCAST     0x4000
152#define RS_BADCRC       0x2000
153#define RS_ODDFRAME     0x1000
154#define RS_TOOLONG      0x0800
155#define RS_TOOSHORT     0x0400
156#define RS_MULTICAST    0x0001
157
158/* Update interrupt status.  */
159static void smc91c111_update(smc91c111_state *s)
160{
161    int level;
162
163    if (s->tx_fifo_len == 0)
164        s->int_level |= INT_TX_EMPTY;
165    if (s->tx_fifo_done_len != 0)
166        s->int_level |= INT_TX;
167    level = (s->int_level & s->int_mask) != 0;
168    qemu_set_irq(s->irq, level);
169}
170
171/* Try to allocate a packet.  Returns 0x80 on failure.  */
172static int smc91c111_allocate_packet(smc91c111_state *s)
173{
174    int i;
175    if (s->allocated == (1 << NUM_PACKETS) - 1) {
176        return 0x80;
177    }
178
179    for (i = 0; i < NUM_PACKETS; i++) {
180        if ((s->allocated & (1 << i)) == 0)
181            break;
182    }
183    s->allocated |= 1 << i;
184    return i;
185}
186
187
188/* Process a pending TX allocate.  */
189static void smc91c111_tx_alloc(smc91c111_state *s)
190{
191    s->tx_alloc = smc91c111_allocate_packet(s);
192    if (s->tx_alloc == 0x80)
193        return;
194    s->int_level |= INT_ALLOC;
195    smc91c111_update(s);
196}
197
198/* Remove and item from the RX FIFO.  */
199static void smc91c111_pop_rx_fifo(smc91c111_state *s)
200{
201    int i;
202
203    s->rx_fifo_len--;
204    if (s->rx_fifo_len) {
205        for (i = 0; i < s->rx_fifo_len; i++)
206            s->rx_fifo[i] = s->rx_fifo[i + 1];
207        s->int_level |= INT_RCV;
208    } else {
209        s->int_level &= ~INT_RCV;
210    }
211    smc91c111_update(s);
212}
213
214/* Remove an item from the TX completion FIFO.  */
215static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
216{
217    int i;
218
219    if (s->tx_fifo_done_len == 0)
220        return;
221    s->tx_fifo_done_len--;
222    for (i = 0; i < s->tx_fifo_done_len; i++)
223        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
224}
225
226/* Release the memory allocated to a packet.  */
227static void smc91c111_release_packet(smc91c111_state *s, int packet)
228{
229    s->allocated &= ~(1 << packet);
230    if (s->tx_alloc == 0x80)
231        smc91c111_tx_alloc(s);
232}
233
234/* Flush the TX FIFO.  */
235static void smc91c111_do_tx(smc91c111_state *s)
236{
237    int i;
238    int len;
239    int control;
240    int packetnum;
241    uint8_t *p;
242
243    if ((s->tcr & TCR_TXEN) == 0)
244        return;
245    if (s->tx_fifo_len == 0)
246        return;
247    for (i = 0; i < s->tx_fifo_len; i++) {
248        packetnum = s->tx_fifo[i];
249        p = &s->data[packetnum][0];
250        /* Set status word.  */
251        *(p++) = 0x01;
252        *(p++) = 0x40;
253        len = *(p++);
254        len |= ((int)*(p++)) << 8;
255        len -= 6;
256        control = p[len + 1];
257        if (control & 0x20)
258            len++;
259        /* ??? This overwrites the data following the buffer.
260           Don't know what real hardware does.  */
261        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
262            memset(p + len, 0, 64 - len);
263            len = 64;
264        }
265#if 0
266        /* The card is supposed to append the CRC to the frame.  However
267           none of the other network traffic has the CRC appended.
268           Suspect this is low level ethernet detail we don't need to worry
269           about.  */
270        add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
271        if (add_crc) {
272            uint32_t crc;
273
274            crc = crc32(~0, p, len);
275            memcpy(p + len, &crc, 4);
276            len += 4;
277        }
278#endif
279        if (s->ctr & CTR_AUTO_RELEASE)
280            /* Race?  */
281            smc91c111_release_packet(s, packetnum);
282        else if (s->tx_fifo_done_len < NUM_PACKETS)
283            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
284        qemu_send_packet(s->vc, p, len);
285    }
286    s->tx_fifo_len = 0;
287    smc91c111_update(s);
288}
289
290/* Add a packet to the TX FIFO.  */
291static void smc91c111_queue_tx(smc91c111_state *s, int packet)
292{
293    if (s->tx_fifo_len == NUM_PACKETS)
294        return;
295    s->tx_fifo[s->tx_fifo_len++] = packet;
296    smc91c111_do_tx(s);
297}
298
299static void smc91c111_reset(smc91c111_state *s)
300{
301    s->bank = 0;
302    s->tx_fifo_len = 0;
303    s->tx_fifo_done_len = 0;
304    s->rx_fifo_len = 0;
305    s->allocated = 0;
306    s->packet_num = 0;
307    s->tx_alloc = 0;
308    s->tcr = 0;
309    s->rcr = 0;
310    s->cr = 0xa0b1;
311    s->ctr = 0x1210;
312    s->ptr = 0;
313    s->ercv = 0x1f;
314    s->int_level = INT_TX_EMPTY;
315    s->int_mask = 0;
316    smc91c111_update(s);
317}
318
319#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
320#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
321
322static void smc91c111_writeb(void *opaque, hwaddr offset,
323                             uint32_t value)
324{
325    smc91c111_state *s = (smc91c111_state *)opaque;
326
327    if (offset == 14) {
328        s->bank = value;
329        return;
330    }
331    if (offset == 15)
332        return;
333    switch (s->bank) {
334    case 0:
335        switch (offset) {
336        case 0: /* TCR */
337            SET_LOW(tcr, value);
338            return;
339        case 1:
340            SET_HIGH(tcr, value);
341            return;
342        case 4: /* RCR */
343            SET_LOW(rcr, value);
344            return;
345        case 5:
346            SET_HIGH(rcr, value);
347            if (s->rcr & RCR_SOFT_RST)
348                smc91c111_reset(s);
349            return;
350        case 10: case 11: /* RPCR */
351            /* Ignored */
352            return;
353        }
354        break;
355
356    case 1:
357        switch (offset) {
358        case 0: /* CONFIG */
359            SET_LOW(cr, value);
360            return;
361        case 1:
362            SET_HIGH(cr,value);
363            return;
364        case 2: case 3: /* BASE */
365        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
366            /* Not implemented.  */
367            return;
368        case 10: /* Genral Purpose */
369            SET_LOW(gpr, value);
370            return;
371        case 11:
372            SET_HIGH(gpr, value);
373            return;
374        case 12: /* Control */
375            if (value & 1)
376                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
377            if (value & 2)
378                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
379            value &= ~3;
380            SET_LOW(ctr, value);
381            return;
382        case 13:
383            SET_HIGH(ctr, value);
384            return;
385        }
386        break;
387
388    case 2:
389        switch (offset) {
390        case 0: /* MMU Command */
391            switch (value >> 5) {
392            case 0: /* no-op */
393                break;
394            case 1: /* Allocate for TX.  */
395                s->tx_alloc = 0x80;
396                s->int_level &= ~INT_ALLOC;
397                smc91c111_update(s);
398                smc91c111_tx_alloc(s);
399                break;
400            case 2: /* Reset MMU.  */
401                s->allocated = 0;
402                s->tx_fifo_len = 0;
403                s->tx_fifo_done_len = 0;
404                s->rx_fifo_len = 0;
405                s->tx_alloc = 0;
406                break;
407            case 3: /* Remove from RX FIFO.  */
408                smc91c111_pop_rx_fifo(s);
409                break;
410            case 4: /* Remove from RX FIFO and release.  */
411                if (s->rx_fifo_len > 0) {
412                    smc91c111_release_packet(s, s->rx_fifo[0]);
413                }
414                smc91c111_pop_rx_fifo(s);
415                break;
416            case 5: /* Release.  */
417                smc91c111_release_packet(s, s->packet_num);
418                break;
419            case 6: /* Add to TX FIFO.  */
420                smc91c111_queue_tx(s, s->packet_num);
421                break;
422            case 7: /* Reset TX FIFO.  */
423                s->tx_fifo_len = 0;
424                s->tx_fifo_done_len = 0;
425                break;
426            }
427            return;
428        case 1:
429            /* Ignore.  */
430            return;
431        case 2: /* Packet Number Register */
432            s->packet_num = value;
433            return;
434        case 3: case 4: case 5:
435            /* Should be readonly, but linux writes to them anyway. Ignore.  */
436            return;
437        case 6: /* Pointer */
438            SET_LOW(ptr, value);
439            return;
440        case 7:
441            SET_HIGH(ptr, value);
442            return;
443        case 8: case 9: case 10: case 11: /* Data */
444            {
445                int p;
446                int n;
447
448                if (s->ptr & 0x8000)
449                    n = s->rx_fifo[0];
450                else
451                    n = s->packet_num;
452                p = s->ptr & 0x07ff;
453                if (s->ptr & 0x4000) {
454                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
455                } else {
456                    p += (offset & 3);
457                }
458                s->data[n][p] = value;
459            }
460            return;
461        case 12: /* Interrupt ACK.  */
462            s->int_level &= ~(value & 0xd6);
463            if (value & INT_TX)
464                smc91c111_pop_tx_fifo_done(s);
465            smc91c111_update(s);
466            return;
467        case 13: /* Interrupt mask.  */
468            s->int_mask = value;
469            smc91c111_update(s);
470            return;
471        }
472        break;;
473
474    case 3:
475        switch (offset) {
476        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
477            /* Multicast table.  */
478            /* Not implemented.  */
479            return;
480        case 8: case 9: /* Management Interface.  */
481            /* Not implemented.  */
482            return;
483        case 12: /* Early receive.  */
484            s->ercv = value & 0x1f;
485        case 13:
486            /* Ignore.  */
487            return;
488        }
489        break;
490    }
491    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
492}
493
494static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
495{
496    smc91c111_state *s = (smc91c111_state *)opaque;
497
498    if (offset == 14) {
499        return s->bank;
500    }
501    if (offset == 15)
502        return 0x33;
503    switch (s->bank) {
504    case 0:
505        switch (offset) {
506        case 0: /* TCR */
507            return s->tcr & 0xff;
508        case 1:
509            return s->tcr >> 8;
510        case 2: /* EPH Status */
511            return 0;
512        case 3:
513            return 0x40;
514        case 4: /* RCR */
515            return s->rcr & 0xff;
516        case 5:
517            return s->rcr >> 8;
518        case 6: /* Counter */
519        case 7:
520            /* Not implemented.  */
521            return 0;
522        case 8: /* Memory size.  */
523            return NUM_PACKETS;
524        case 9: /* Free memory available.  */
525            {
526                int i;
527                int n;
528                n = 0;
529                for (i = 0; i < NUM_PACKETS; i++) {
530                    if (s->allocated & (1 << i))
531                        n++;
532                }
533                return n;
534            }
535        case 10: case 11: /* RPCR */
536            /* Not implemented.  */
537            return 0;
538        }
539        break;
540
541    case 1:
542        switch (offset) {
543        case 0: /* CONFIG */
544            return s->cr & 0xff;
545        case 1:
546            return s->cr >> 8;
547        case 2: case 3: /* BASE */
548            /* Not implemented.  */
549            return 0;
550        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
551            return s->macaddr[offset - 4];
552        case 10: /* General Purpose */
553            return s->gpr & 0xff;
554        case 11:
555            return s->gpr >> 8;
556        case 12: /* Control */
557            return s->ctr & 0xff;
558        case 13:
559            return s->ctr >> 8;
560        }
561        break;
562
563    case 2:
564        switch (offset) {
565        case 0: case 1: /* MMUCR Busy bit.  */
566            return 0;
567        case 2: /* Packet Number.  */
568            return s->packet_num;
569        case 3: /* Allocation Result.  */
570            return s->tx_alloc;
571        case 4: /* TX FIFO */
572            if (s->tx_fifo_done_len == 0)
573                return 0x80;
574            else
575                return s->tx_fifo_done[0];
576        case 5: /* RX FIFO */
577            if (s->rx_fifo_len == 0)
578                return 0x80;
579            else
580                return s->rx_fifo[0];
581        case 6: /* Pointer */
582            return s->ptr & 0xff;
583        case 7:
584            return (s->ptr >> 8) & 0xf7;
585        case 8: case 9: case 10: case 11: /* Data */
586            {
587                int p;
588                int n;
589
590                if (s->ptr & 0x8000)
591                    n = s->rx_fifo[0];
592                else
593                    n = s->packet_num;
594                p = s->ptr & 0x07ff;
595                if (s->ptr & 0x4000) {
596                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
597                } else {
598                    p += (offset & 3);
599                }
600                return s->data[n][p];
601            }
602        case 12: /* Interrupt status.  */
603            return s->int_level;
604        case 13: /* Interrupt mask.  */
605            return s->int_mask;
606        }
607        break;
608
609    case 3:
610        switch (offset) {
611        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
612            /* Multicast table.  */
613            /* Not implemented.  */
614            return 0;
615        case 8: /* Management Interface.  */
616            /* Not implemented.  */
617            return 0x30;
618        case 9:
619            return 0x33;
620        case 10: /* Revision.  */
621            return 0x91;
622        case 11:
623            return 0x33;
624        case 12:
625            return s->ercv;
626        case 13:
627            return 0;
628        }
629        break;
630    }
631    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
632    return 0;
633}
634
635static void smc91c111_writew(void *opaque, hwaddr offset,
636                             uint32_t value)
637{
638    smc91c111_writeb(opaque, offset, value & 0xff);
639    smc91c111_writeb(opaque, offset + 1, value >> 8);
640}
641
642static void smc91c111_writel(void *opaque, hwaddr offset,
643                             uint32_t value)
644{
645    /* 32-bit writes to offset 0xc only actually write to the bank select
646       register (offset 0xe)  */
647    if (offset != 0xc)
648        smc91c111_writew(opaque, offset, value & 0xffff);
649    smc91c111_writew(opaque, offset + 2, value >> 16);
650}
651
652static uint32_t smc91c111_readw(void *opaque, hwaddr offset)
653{
654    uint32_t val;
655    val = smc91c111_readb(opaque, offset);
656    val |= smc91c111_readb(opaque, offset + 1) << 8;
657    return val;
658}
659
660static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
661{
662    uint32_t val;
663    val = smc91c111_readw(opaque, offset);
664    val |= smc91c111_readw(opaque, offset + 2) << 16;
665    return val;
666}
667
668static int smc91c111_can_receive(VLANClientState *vc)
669{
670    smc91c111_state *s = vc->opaque;
671
672    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
673        return 1;
674    if (s->allocated == (1 << NUM_PACKETS) - 1)
675        return 0;
676    return 1;
677}
678
679static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
680{
681    smc91c111_state *s = vc->opaque;
682    int status;
683    int packetsize;
684    uint32_t crc;
685    int packetnum;
686    uint8_t *p;
687
688    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
689        return -1;
690    /* Short packets are padded with zeros.  Receiving a packet
691       < 64 bytes long is considered an error condition.  */
692    if (size < 64)
693        packetsize = 64;
694    else
695        packetsize = (size & ~1);
696    packetsize += 6;
697    crc = (s->rcr & RCR_STRIP_CRC) == 0;
698    if (crc)
699        packetsize += 4;
700    /* TODO: Flag overrun and receive errors.  */
701    if (packetsize > 2048)
702        return -1;
703    packetnum = smc91c111_allocate_packet(s);
704    if (packetnum == 0x80)
705        return -1;
706    s->rx_fifo[s->rx_fifo_len++] = packetnum;
707
708    p = &s->data[packetnum][0];
709    /* ??? Multicast packets?  */
710    status = 0;
711    if (size > 1518)
712        status |= RS_TOOLONG;
713    if (size & 1)
714        status |= RS_ODDFRAME;
715    *(p++) = status & 0xff;
716    *(p++) = status >> 8;
717    *(p++) = packetsize & 0xff;
718    *(p++) = packetsize >> 8;
719    memcpy(p, buf, size & ~1);
720    p += (size & ~1);
721    /* Pad short packets.  */
722    if (size < 64) {
723        int pad;
724
725        if (size & 1)
726            *(p++) = buf[size - 1];
727        pad = 64 - size;
728        memset(p, 0, pad);
729        p += pad;
730        size = 64;
731    }
732    /* It's not clear if the CRC should go before or after the last byte in
733       odd sized packets.  Linux disables the CRC, so that's no help.
734       The pictures in the documentation show the CRC aligned on a 16-bit
735       boundary before the last odd byte, so that's what we do.  */
736    if (crc) {
737        crc = crc32(~0, buf, size);
738        *(p++) = crc & 0xff; crc >>= 8;
739        *(p++) = crc & 0xff; crc >>= 8;
740        *(p++) = crc & 0xff; crc >>= 8;
741        *(p++) = crc & 0xff; crc >>= 8;
742    }
743    if (size & 1) {
744        *(p++) = buf[size - 1];
745        *(p++) = 0x60;
746    } else {
747        *(p++) = 0;
748        *(p++) = 0x40;
749    }
750    /* TODO: Raise early RX interrupt?  */
751    s->int_level |= INT_RCV;
752    smc91c111_update(s);
753
754    return size;
755}
756
757static CPUReadMemoryFunc *smc91c111_readfn[] = {
758    smc91c111_readb,
759    smc91c111_readw,
760    smc91c111_readl
761};
762
763static CPUWriteMemoryFunc *smc91c111_writefn[] = {
764    smc91c111_writeb,
765    smc91c111_writew,
766    smc91c111_writel
767};
768
769static void smc91c111_cleanup(VLANClientState *vc)
770{
771    smc91c111_state *s = vc->opaque;
772
773    cpu_unregister_io_memory(s->mmio_index);
774    g_free(s);
775}
776
777static void smc91c111_init1(SysBusDevice *dev)
778{
779    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
780
781    s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
782                                           smc91c111_writefn, s);
783    sysbus_init_mmio(dev, 16, s->mmio_index);
784    sysbus_init_irq(dev, &s->irq);
785    qdev_get_macaddr(&dev->qdev, s->macaddr);
786
787    smc91c111_reset(s);
788
789    s->vc = qdev_get_vlan_client(&dev->qdev,
790                                 smc91c111_can_receive, smc91c111_receive, NULL,
791                                 smc91c111_cleanup, s);
792    qemu_format_nic_info_str(s->vc, s->macaddr);
793
794    register_savevm(NULL, "smc91c111", 0, SMC91C111_SAVE_VERSION,
795                    smc91c111_save, smc91c111_load, s);
796}
797
798static void smc91c111_register_devices(void)
799{
800    sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1);
801}
802
803/* Legacy helper function.  Should go away when machine config files are
804   implemented.  */
805void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
806{
807    DeviceState *dev;
808    SysBusDevice *s;
809
810    qemu_check_nic_model(nd, "smc91c111");
811    dev = qdev_create(NULL, "smc91c111");
812    qdev_set_netdev(dev, nd);
813    qdev_init(dev);
814    s = sysbus_from_qdev(dev);
815    sysbus_mmio_map(s, 0, base);
816    sysbus_connect_irq(s, 0, irq);
817}
818
819device_init(smc91c111_register_devices)
820