xref: /qemu/hw/net/smc91c111.c (revision 14da56169886e90b3313d8128aecacf261ded607)
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 #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->nic->nc, 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     offset = offset & 0xf;
254     if (offset == 14) {
255         s->bank = value;
256         return;
257     }
258     if (offset == 15)
259         return;
260     switch (s->bank) {
261     case 0:
262         switch (offset) {
263         case 0: /* TCR */
264             SET_LOW(tcr, value);
265             return;
266         case 1:
267             SET_HIGH(tcr, value);
268             return;
269         case 4: /* RCR */
270             SET_LOW(rcr, value);
271             return;
272         case 5:
273             SET_HIGH(rcr, value);
274             if (s->rcr & RCR_SOFT_RST)
275                 smc91c111_reset(s);
276             return;
277         case 10: case 11: /* RPCR */
278             /* Ignored */
279             return;
280         case 12: case 13: /* Reserved */
281             return;
282         }
283         break;
284 
285     case 1:
286         switch (offset) {
287         case 0: /* CONFIG */
288             SET_LOW(cr, value);
289             return;
290         case 1:
291             SET_HIGH(cr,value);
292             return;
293         case 2: case 3: /* BASE */
294         case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
295             /* Not implemented.  */
296             return;
297         case 10: /* Genral Purpose */
298             SET_LOW(gpr, value);
299             return;
300         case 11:
301             SET_HIGH(gpr, value);
302             return;
303         case 12: /* Control */
304             if (value & 1)
305                 fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
306             if (value & 2)
307                 fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
308             value &= ~3;
309             SET_LOW(ctr, value);
310             return;
311         case 13:
312             SET_HIGH(ctr, value);
313             return;
314         }
315         break;
316 
317     case 2:
318         switch (offset) {
319         case 0: /* MMU Command */
320             switch (value >> 5) {
321             case 0: /* no-op */
322                 break;
323             case 1: /* Allocate for TX.  */
324                 s->tx_alloc = 0x80;
325                 s->int_level &= ~INT_ALLOC;
326                 smc91c111_update(s);
327                 smc91c111_tx_alloc(s);
328                 break;
329             case 2: /* Reset MMU.  */
330                 s->allocated = 0;
331                 s->tx_fifo_len = 0;
332                 s->tx_fifo_done_len = 0;
333                 s->rx_fifo_len = 0;
334                 s->tx_alloc = 0;
335                 break;
336             case 3: /* Remove from RX FIFO.  */
337                 smc91c111_pop_rx_fifo(s);
338                 break;
339             case 4: /* Remove from RX FIFO and release.  */
340                 if (s->rx_fifo_len > 0) {
341                     smc91c111_release_packet(s, s->rx_fifo[0]);
342                 }
343                 smc91c111_pop_rx_fifo(s);
344                 break;
345             case 5: /* Release.  */
346                 smc91c111_release_packet(s, s->packet_num);
347                 break;
348             case 6: /* Add to TX FIFO.  */
349                 smc91c111_queue_tx(s, s->packet_num);
350                 break;
351             case 7: /* Reset TX FIFO.  */
352                 s->tx_fifo_len = 0;
353                 s->tx_fifo_done_len = 0;
354                 break;
355             }
356             return;
357         case 1:
358             /* Ignore.  */
359             return;
360         case 2: /* Packet Number Register */
361             s->packet_num = value;
362             return;
363         case 3: case 4: case 5:
364             /* Should be readonly, but linux writes to them anyway. Ignore.  */
365             return;
366         case 6: /* Pointer */
367             SET_LOW(ptr, value);
368             return;
369         case 7:
370             SET_HIGH(ptr, value);
371             return;
372         case 8: case 9: case 10: case 11: /* Data */
373             {
374                 int p;
375                 int n;
376 
377                 if (s->ptr & 0x8000)
378                     n = s->rx_fifo[0];
379                 else
380                     n = s->packet_num;
381                 p = s->ptr & 0x07ff;
382                 if (s->ptr & 0x4000) {
383                     s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
384                 } else {
385                     p += (offset & 3);
386                 }
387                 s->data[n][p] = value;
388             }
389             return;
390         case 12: /* Interrupt ACK.  */
391             s->int_level &= ~(value & 0xd6);
392             if (value & INT_TX)
393                 smc91c111_pop_tx_fifo_done(s);
394             smc91c111_update(s);
395             return;
396         case 13: /* Interrupt mask.  */
397             s->int_mask = value;
398             smc91c111_update(s);
399             return;
400         }
401         break;;
402 
403     case 3:
404         switch (offset) {
405         case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
406             /* Multicast table.  */
407             /* Not implemented.  */
408             return;
409         case 8: case 9: /* Management Interface.  */
410             /* Not implemented.  */
411             return;
412         case 12: /* Early receive.  */
413             s->ercv = value & 0x1f;
414         case 13:
415             /* Ignore.  */
416             return;
417         }
418         break;
419     }
420     hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
421 }
422 
423 static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
424 {
425     smc91c111_state *s = (smc91c111_state *)opaque;
426 
427     offset = offset & 0xf;
428     if (offset == 14) {
429         return s->bank;
430     }
431     if (offset == 15)
432         return 0x33;
433     switch (s->bank) {
434     case 0:
435         switch (offset) {
436         case 0: /* TCR */
437             return s->tcr & 0xff;
438         case 1:
439             return s->tcr >> 8;
440         case 2: /* EPH Status */
441             return 0;
442         case 3:
443             return 0x40;
444         case 4: /* RCR */
445             return s->rcr & 0xff;
446         case 5:
447             return s->rcr >> 8;
448         case 6: /* Counter */
449         case 7:
450             /* Not implemented.  */
451             return 0;
452         case 8: /* Memory size.  */
453             return NUM_PACKETS;
454         case 9: /* Free memory available.  */
455             {
456                 int i;
457                 int n;
458                 n = 0;
459                 for (i = 0; i < NUM_PACKETS; i++) {
460                     if (s->allocated & (1 << i))
461                         n++;
462                 }
463                 return n;
464             }
465         case 10: case 11: /* RPCR */
466             /* Not implemented.  */
467             return 0;
468         case 12: case 13: /* Reserved */
469             return 0;
470         }
471         break;
472 
473     case 1:
474         switch (offset) {
475         case 0: /* CONFIG */
476             return s->cr & 0xff;
477         case 1:
478             return s->cr >> 8;
479         case 2: case 3: /* BASE */
480             /* Not implemented.  */
481             return 0;
482         case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
483             return s->conf.macaddr.a[offset - 4];
484         case 10: /* General Purpose */
485             return s->gpr & 0xff;
486         case 11:
487             return s->gpr >> 8;
488         case 12: /* Control */
489             return s->ctr & 0xff;
490         case 13:
491             return s->ctr >> 8;
492         }
493         break;
494 
495     case 2:
496         switch (offset) {
497         case 0: case 1: /* MMUCR Busy bit.  */
498             return 0;
499         case 2: /* Packet Number.  */
500             return s->packet_num;
501         case 3: /* Allocation Result.  */
502             return s->tx_alloc;
503         case 4: /* TX FIFO */
504             if (s->tx_fifo_done_len == 0)
505                 return 0x80;
506             else
507                 return s->tx_fifo_done[0];
508         case 5: /* RX FIFO */
509             if (s->rx_fifo_len == 0)
510                 return 0x80;
511             else
512                 return s->rx_fifo[0];
513         case 6: /* Pointer */
514             return s->ptr & 0xff;
515         case 7:
516             return (s->ptr >> 8) & 0xf7;
517         case 8: case 9: case 10: case 11: /* Data */
518             {
519                 int p;
520                 int n;
521 
522                 if (s->ptr & 0x8000)
523                     n = s->rx_fifo[0];
524                 else
525                     n = s->packet_num;
526                 p = s->ptr & 0x07ff;
527                 if (s->ptr & 0x4000) {
528                     s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
529                 } else {
530                     p += (offset & 3);
531                 }
532                 return s->data[n][p];
533             }
534         case 12: /* Interrupt status.  */
535             return s->int_level;
536         case 13: /* Interrupt mask.  */
537             return s->int_mask;
538         }
539         break;
540 
541     case 3:
542         switch (offset) {
543         case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
544             /* Multicast table.  */
545             /* Not implemented.  */
546             return 0;
547         case 8: /* Management Interface.  */
548             /* Not implemented.  */
549             return 0x30;
550         case 9:
551             return 0x33;
552         case 10: /* Revision.  */
553             return 0x91;
554         case 11:
555             return 0x33;
556         case 12:
557             return s->ercv;
558         case 13:
559             return 0;
560         }
561         break;
562     }
563     hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
564     return 0;
565 }
566 
567 static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
568                              uint32_t value)
569 {
570     smc91c111_writeb(opaque, offset, value & 0xff);
571     smc91c111_writeb(opaque, offset + 1, value >> 8);
572 }
573 
574 static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
575                              uint32_t value)
576 {
577     /* 32-bit writes to offset 0xc only actually write to the bank select
578        register (offset 0xe)  */
579     if (offset != 0xc)
580         smc91c111_writew(opaque, offset, value & 0xffff);
581     smc91c111_writew(opaque, offset + 2, value >> 16);
582 }
583 
584 static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
585 {
586     uint32_t val;
587     val = smc91c111_readb(opaque, offset);
588     val |= smc91c111_readb(opaque, offset + 1) << 8;
589     return val;
590 }
591 
592 static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
593 {
594     uint32_t val;
595     val = smc91c111_readw(opaque, offset);
596     val |= smc91c111_readw(opaque, offset + 2) << 16;
597     return val;
598 }
599 
600 static int smc91c111_can_receive(VLANClientState *nc)
601 {
602     smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
603 
604     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
605         return 1;
606     if (s->allocated == (1 << NUM_PACKETS) - 1)
607         return 0;
608     return 1;
609 }
610 
611 static ssize_t smc91c111_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
612 {
613     smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
614     int status;
615     int packetsize;
616     uint32_t crc;
617     int packetnum;
618     uint8_t *p;
619 
620     if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
621         return -1;
622     /* Short packets are padded with zeros.  Receiving a packet
623        < 64 bytes long is considered an error condition.  */
624     if (size < 64)
625         packetsize = 64;
626     else
627         packetsize = (size & ~1);
628     packetsize += 6;
629     crc = (s->rcr & RCR_STRIP_CRC) == 0;
630     if (crc)
631         packetsize += 4;
632     /* TODO: Flag overrun and receive errors.  */
633     if (packetsize > 2048)
634         return -1;
635     packetnum = smc91c111_allocate_packet(s);
636     if (packetnum == 0x80)
637         return -1;
638     s->rx_fifo[s->rx_fifo_len++] = packetnum;
639 
640     p = &s->data[packetnum][0];
641     /* ??? Multicast packets?  */
642     status = 0;
643     if (size > 1518)
644         status |= RS_TOOLONG;
645     if (size & 1)
646         status |= RS_ODDFRAME;
647     *(p++) = status & 0xff;
648     *(p++) = status >> 8;
649     *(p++) = packetsize & 0xff;
650     *(p++) = packetsize >> 8;
651     memcpy(p, buf, size & ~1);
652     p += (size & ~1);
653     /* Pad short packets.  */
654     if (size < 64) {
655         int pad;
656 
657         if (size & 1)
658             *(p++) = buf[size - 1];
659         pad = 64 - size;
660         memset(p, 0, pad);
661         p += pad;
662         size = 64;
663     }
664     /* It's not clear if the CRC should go before or after the last byte in
665        odd sized packets.  Linux disables the CRC, so that's no help.
666        The pictures in the documentation show the CRC aligned on a 16-bit
667        boundary before the last odd byte, so that's what we do.  */
668     if (crc) {
669         crc = crc32(~0, buf, size);
670         *(p++) = crc & 0xff; crc >>= 8;
671         *(p++) = crc & 0xff; crc >>= 8;
672         *(p++) = crc & 0xff; crc >>= 8;
673         *(p++) = crc & 0xff; crc >>= 8;
674     }
675     if (size & 1) {
676         *(p++) = buf[size - 1];
677         *(p++) = 0x60;
678     } else {
679         *(p++) = 0;
680         *(p++) = 0x40;
681     }
682     /* TODO: Raise early RX interrupt?  */
683     s->int_level |= INT_RCV;
684     smc91c111_update(s);
685 
686     return size;
687 }
688 
689 static CPUReadMemoryFunc * const smc91c111_readfn[] = {
690     smc91c111_readb,
691     smc91c111_readw,
692     smc91c111_readl
693 };
694 
695 static CPUWriteMemoryFunc * const smc91c111_writefn[] = {
696     smc91c111_writeb,
697     smc91c111_writew,
698     smc91c111_writel
699 };
700 
701 static void smc91c111_cleanup(VLANClientState *nc)
702 {
703     smc91c111_state *s = DO_UPCAST(NICState, nc, nc)->opaque;
704 
705     s->nic = NULL;
706 }
707 
708 static NetClientInfo net_smc91c111_info = {
709     .type = NET_CLIENT_TYPE_NIC,
710     .size = sizeof(NICState),
711     .can_receive = smc91c111_can_receive,
712     .receive = smc91c111_receive,
713     .cleanup = smc91c111_cleanup,
714 };
715 
716 static int smc91c111_init1(SysBusDevice *dev)
717 {
718     smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
719 
720     s->mmio_index = cpu_register_io_memory(smc91c111_readfn,
721                                            smc91c111_writefn, s);
722     sysbus_init_mmio(dev, 16, s->mmio_index);
723     sysbus_init_irq(dev, &s->irq);
724     qemu_macaddr_default_if_unset(&s->conf.macaddr);
725 
726     smc91c111_reset(s);
727 
728     s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
729                           dev->qdev.info->name, dev->qdev.id, s);
730     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
731     /* ??? Save/restore.  */
732     return 0;
733 }
734 
735 static SysBusDeviceInfo smc91c111_info = {
736     .init = smc91c111_init1,
737     .qdev.name  = "smc91c111",
738     .qdev.size  = sizeof(smc91c111_state),
739     .qdev.props = (Property[]) {
740         DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
741         DEFINE_PROP_END_OF_LIST(),
742     }
743 };
744 
745 static void smc91c111_register_devices(void)
746 {
747     sysbus_register_withprop(&smc91c111_info);
748 }
749 
750 /* Legacy helper function.  Should go away when machine config files are
751    implemented.  */
752 void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
753 {
754     DeviceState *dev;
755     SysBusDevice *s;
756 
757     qemu_check_nic_model(nd, "smc91c111");
758     dev = qdev_create(NULL, "smc91c111");
759     qdev_set_nic_properties(dev, nd);
760     qdev_init_nofail(dev);
761     s = sysbus_from_qdev(dev);
762     sysbus_mmio_map(s, 0, base);
763     sysbus_connect_irq(s, 0, irq);
764 }
765 
766 device_init(smc91c111_register_devices)
767