• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     uint16_t tcr;
23     uint16_t rcr;
24     uint16_t cr;
25     uint16_t ctr;
26     uint16_t gpr;
27     uint16_t ptr;
28     uint16_t ercv;
29     qemu_irq irq;
30     int bank;
31     int packet_num;
32     int tx_alloc;
33     /* Bitmask of allocated packets.  */
34     int allocated;
35     int tx_fifo_len;
36     int tx_fifo[NUM_PACKETS];
37     int rx_fifo_len;
38     int rx_fifo[NUM_PACKETS];
39     int tx_fifo_done_len;
40     int tx_fifo_done[NUM_PACKETS];
41     /* Packet buffer memory.  */
42     uint8_t data[NUM_PACKETS][2048];
43     uint8_t int_level;
44     uint8_t int_mask;
45     uint8_t macaddr[6];
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.  */
smc91c111_update(smc91c111_state * s)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.  */
smc91c111_allocate_packet(smc91c111_state * s)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.  */
smc91c111_tx_alloc(smc91c111_state * s)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.  */
smc91c111_pop_rx_fifo(smc91c111_state * s)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.  */
smc91c111_pop_tx_fifo_done(smc91c111_state * s)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.  */
smc91c111_release_packet(smc91c111_state * s,int 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.  */
smc91c111_do_tx(smc91c111_state * s)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.  */
smc91c111_queue_tx(smc91c111_state * s,int packet)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 
smc91c111_reset(smc91c111_state * s)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 
smc91c111_writeb(void * opaque,target_phys_addr_t offset,uint32_t value)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 
smc91c111_readb(void * opaque,target_phys_addr_t offset)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->macaddr[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 
smc91c111_writew(void * opaque,target_phys_addr_t offset,uint32_t value)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 
smc91c111_writel(void * opaque,target_phys_addr_t offset,uint32_t value)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 
smc91c111_readw(void * opaque,target_phys_addr_t offset)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 
smc91c111_readl(void * opaque,target_phys_addr_t offset)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 
smc91c111_can_receive(VLANClientState * vc)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 
smc91c111_receive(VLANClientState * vc,const uint8_t * buf,size_t size)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 *smc91c111_readfn[] = {
684     smc91c111_readb,
685     smc91c111_readw,
686     smc91c111_readl
687 };
688 
689 static CPUWriteMemoryFunc *smc91c111_writefn[] = {
690     smc91c111_writeb,
691     smc91c111_writew,
692     smc91c111_writel
693 };
694 
smc91c111_cleanup(VLANClientState * vc)695 static void smc91c111_cleanup(VLANClientState *vc)
696 {
697     smc91c111_state *s = vc->opaque;
698 
699     cpu_unregister_io_memory(s->mmio_index);
700     qemu_free(s);
701 }
702 
smc91c111_init1(SysBusDevice * dev)703 static void smc91c111_init1(SysBusDevice *dev)
704 {
705     smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
706 
707     s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
708                                            smc91c111_writefn, s);
709     sysbus_init_mmio(dev, 16, s->mmio_index);
710     sysbus_init_irq(dev, &s->irq);
711     qdev_get_macaddr(&dev->qdev, s->macaddr);
712 
713     smc91c111_reset(s);
714 
715     s->vc = qdev_get_vlan_client(&dev->qdev,
716                                  smc91c111_can_receive, smc91c111_receive, NULL,
717                                  smc91c111_cleanup, s);
718     qemu_format_nic_info_str(s->vc, s->macaddr);
719     /* ??? Save/restore.  */
720 }
721 
smc91c111_register_devices(void)722 static void smc91c111_register_devices(void)
723 {
724     sysbus_register_dev("smc91c111", sizeof(smc91c111_state), smc91c111_init1);
725 }
726 
727 /* Legacy helper function.  Should go away when machine config files are
728    implemented.  */
smc91c111_init(NICInfo * nd,uint32_t base,qemu_irq irq)729 void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
730 {
731     DeviceState *dev;
732     SysBusDevice *s;
733 
734     qemu_check_nic_model(nd, "smc91c111");
735     dev = qdev_create(NULL, "smc91c111");
736     qdev_set_netdev(dev, nd);
737     qdev_init(dev);
738     s = sysbus_from_qdev(dev);
739     sysbus_mmio_map(s, 0, base);
740     sysbus_connect_irq(s, 0, irq);
741 }
742 
743 device_init(smc91c111_register_devices)
744