Back out of hw-main _callback -> _descriptor changes
[external/binutils.git] / sim / mn10300 / dv-mn103int.c
1 /*  This file is part of the program GDB, the GU debugger.
2     
3     Copyright (C) 1998 Free Software Foundation, Inc.
4     Contributed by Cygnus Solutions.
5     
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10     
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15     
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19     
20     */
21
22
23 #include "sim-main.h"
24 #include "hw-base.h"
25
26 /* DEVICE
27
28    
29    mn103int - mn10300 interrupt controller
30
31    
32    DESCRIPTION
33
34    
35    Implements the mn10300 interrupt controller described in the
36    mn10300 user guide.
37
38
39    PROPERTIES
40    
41
42    reg = <icr-adr> <icr-siz> <iagr-adr> <iadr-siz> <extmd-adr> <extmd-siz>
43
44    Specify the address of the ICR (total of 25 registers), IAGR and
45    EXTMD registers (within the parent bus).
46
47    The reg property value `0x34000100 0x68 0x34000200 0x8 0x3400280
48    0x8' locates the interrupt controller at the addresses specified in
49    the mn10300 interrupt controller user guide.
50
51
52    PORTS
53
54
55    nmi (output)
56
57    Non-maskable interrupt output port.  An event on this output ports
58    indicates a NMI request from the interrupt controller.  The value
59    attached to the event should be ignored.
60
61
62    level (output)
63
64    Maskable interrupt level output port.  An event on this output port
65    indicates a maskable interrupt request at the specified level.  The
66    event value defines the level being requested.
67
68    The interrupt controller will generate an event on this port
69    whenever there is a change to the internal state of the interrupt
70    controller.
71
72
73    ack (input)
74
75    Signal from processor indicating that a maskable interrupt has been
76    accepted and the interrupt controller should latch the IAGR with
77    value of the current highest priority interrupting group.
78
79    The event value is the interrupt level being accepted by the
80    processor.  It should be consistent with the most recent LEVEL sent
81    to the processor from the interrupt controller.
82
83
84    int[0..100] (input)
85
86    Level or edge triggered interrupt input port.  Each of the 25
87    groups (0..24) can have up to 4 (0..3) interrupt inputs.  The
88    interpretation of a port event/value is determined by the
89    configuration of the corresponding interrupt group.
90
91    For convenience, numerous aliases to these interrupt inputs are
92    provided.
93
94
95    BUGS
96
97
98    For edge triggered interrupts, the interrupt controller does not
99    differentiate between POSITIVE (rising) and NEGATIVE (falling)
100    edges.  Instead any input port event is considered to be an
101    interrupt trigger.
102
103    For level sensative interrupts, the interrupt controller ignores
104    active HIGH/LOW settings and instead always interprets a nonzero
105    port value as an interupt assertion and a zero port value as a
106    negation.
107
108    */
109
110
111 /* The interrupt groups - numbered according to mn10300 convention */
112
113 enum mn103int_trigger {
114   ACTIVE_LOW,
115   ACTIVE_HIGH,
116   POSITIVE_EDGE,
117   NEGATIVE_EDGE,
118 };
119
120 enum mn103int_type {
121   NMI_GROUP,
122   LEVEL_GROUP,
123 };
124
125 struct mn103int_group {
126   int gid;
127   int level;
128   unsigned enable;
129   unsigned request;
130   unsigned input;
131   enum mn103int_trigger trigger;
132   enum mn103int_type type;
133 };
134
135 enum {
136   FIRST_NMI_GROUP = 0,
137   LAST_NMI_GROUP = 1,
138   FIRST_LEVEL_GROUP = 2,
139   LAST_LEVEL_GROUP = 24,
140   NR_GROUPS,
141 };
142
143 enum {
144   LOWEST_LEVEL = 7,
145 };
146
147 /* The interrupt controller register address blocks */
148
149 struct mn103int_block {
150   unsigned_word base;
151   unsigned_word bound;
152 };
153
154 enum { ICR_BLOCK, IAGR_BLOCK, EXTMD_BLOCK, NR_BLOCKS };
155
156
157 struct mn103int {
158   struct mn103int_block block[NR_BLOCKS];
159   struct mn103int_group group[NR_GROUPS];
160   unsigned interrupt_accepted_group;
161 };
162
163
164
165 /* output port ID's */ 
166
167 enum {
168   NMI_PORT,
169   LEVEL_PORT,
170 };
171
172
173 /* input port ID's */
174
175 enum {
176   G0_PORT = 0,
177   G1_PORT = 4,
178   G2_PORT = 8,
179   G3_PORT = 12,
180   G4_PORT = 16,
181   G5_PORT = 20,
182   G6_PORT = 24,
183   G7_PORT = 28,
184   G8_PORT = 32,
185   G9_PORT = 36,
186   G10_PORT = 40,
187   G11_PORT = 44,
188   G12_PORT = 48,
189   G13_PORT = 52,
190   G14_PORT = 56,
191   G15_PORT = 60,
192   G16_PORT = 64,
193   G17_PORT = 68,
194   G18_PORT = 72,
195   G19_PORT = 76,
196   G20_PORT = 80,
197   G21_PORT = 84,
198   G22_PORT = 88,
199   G23_PORT = 92,
200   G24_PORT = 96,
201   NR_G_PORTS = 100,
202   ACK_PORT,
203 };
204
205 static const struct hw_port_descriptor mn103int_ports[] = {
206
207   /* interrupt outputs */
208
209   { "nmi", NMI_PORT, 0, output_port, },
210   { "level", LEVEL_PORT, 0, output_port, },
211
212   /* interrupt ack (latch) input from cpu */
213
214   { "ack", ACK_PORT, 0, input_port, },
215
216   /* interrupt inputs (as names) */
217
218   { "nmirq", G0_PORT + 0, 0, input_port, },
219   { "watchdog", G0_PORT + 1, 0, input_port, },
220   { "syserr", G0_PORT + 2, 0, input_port, },
221
222   { "timer-0-underflow", G2_PORT + 0, 0, input_port, },
223   { "timer-1-underflow", G2_PORT + 1, 0, input_port, },
224   { "timer-2-underflow", G2_PORT + 2, 0, input_port, },
225   { "timer-3-underflow", G2_PORT + 3, 0, input_port, },
226   { "timer-4-underflow", G3_PORT + 0, 0, input_port, },
227   { "timer-5-underflow", G3_PORT + 1, 0, input_port, },
228   { "timer-6-underflow", G3_PORT + 2, 0, input_port, },
229   { "timer-7-underflow", G3_PORT + 3, 0, input_port, },
230
231   { "timer-8-underflow", G4_PORT + 0, 0, input_port, },
232   { "timer-8-compare-a", G4_PORT + 1, 0, input_port, },
233   { "timer-8-compare-b", G4_PORT + 2, 0, input_port, },
234
235   { "timer-9-underflow", G5_PORT + 0, 0, input_port, },
236   { "timer-9-compare-a", G5_PORT + 1, 0, input_port, },
237   { "timer-9-compare-b", G5_PORT + 2, 0, input_port, },
238
239   { "timer-10-underflow", G6_PORT + 0, 0, input_port, },
240   { "timer-10-compare-a", G6_PORT + 1, 0, input_port, },
241   { "timer-10-compare-b", G6_PORT + 2, 0, input_port, },
242   { "timer-10-compare-c", G6_PORT + 3, 0, input_port, },
243
244   { "timer-11-underflow", G7_PORT + 0, 0, input_port, },
245   { "timer-11-compare-a", G7_PORT + 1, 0, input_port, },
246   { "timer-11-compare-b", G7_PORT + 2, 0, input_port, },
247   { "timer-11-compare-c", G7_PORT + 3, 0, input_port, },
248
249   { "timer-12-underflow", G8_PORT + 0, 0, input_port, },
250   { "timer-12-compare-a", G8_PORT + 1, 0, input_port, },
251   { "timer-12-compare-b", G8_PORT + 2, 0, input_port, },
252   { "timer-12-compare-c", G8_PORT + 3, 0, input_port, },
253
254   { "timer-11-compare-d", G9_PORT + 0, 0, input_port, },
255   { "timer-12-compare-d", G9_PORT + 1, 0, input_port, },
256
257   { "dma-0-end", G10_PORT, 0, input_port, },
258   { "dma-1-end", G11_PORT, 0, input_port, },
259   { "dma-2-end", G12_PORT, 0, input_port, },
260   { "dma-3-end", G13_PORT, 0, input_port, },
261
262   { "serial-0-recieve", G14_PORT + 0, 0, input_port, },
263   { "serial-0-transmit", G14_PORT + 1, 0, input_port, },
264
265   { "serial-1-recieve", G15_PORT + 0, 0, input_port, },
266   { "serial-1-transmit", G15_PORT + 1, 0, input_port, },
267
268   { "irq-0", G16_PORT, 0, input_port, },
269   { "irq-1", G17_PORT, 0, input_port, },
270   { "irq-2", G18_PORT, 0, input_port, },
271   { "irq-3", G19_PORT, 0, input_port, },
272   { "irq-4", G20_PORT, 0, input_port, },
273   { "irq-5", G21_PORT, 0, input_port, },
274   { "irq-6", G22_PORT, 0, input_port, },
275   { "irq-7", G23_PORT, 0, input_port, },
276
277   { "ad-end", G24_PORT, 0, input_port, },
278
279   /* interrupt inputs (as generic numbers) */
280
281   { "int", 0, NR_G_PORTS, input_port, },
282
283   { NULL, },
284 };
285
286
287 /* Macros for extracting/restoring the various register bits */
288
289 #define EXTRACT_ID(X) (LSEXTRACTED8 ((X), 3, 0))
290 #define INSERT_ID(X) (LSINSERTED8 ((X), 3, 0))
291
292 #define EXTRACT_IR(X) (LSEXTRACTED8 ((X), 7, 4))
293 #define INSERT_IR(X) (LSINSERTED8 ((X), 7, 4))
294
295 #define EXTRACT_IE(X) (LSEXTRACTED8 ((X), 3, 0))
296 #define INSERT_IE(X) (LSINSERTED8 ((X), 3, 0))
297
298 #define EXTRACT_LV(X) (LSEXTRACTED8 ((X), 6, 4))
299 #define INSERT_LV(X) (LSINSERTED8 ((X), 6, 4))
300
301
302
303 /* Finish off the partially created hw device.  Attach our local
304    callbacks.  Wire up our port names etc */
305
306 static hw_io_read_buffer_callback mn103int_io_read_buffer;
307 static hw_io_write_buffer_callback mn103int_io_write_buffer;
308 static hw_port_event_callback mn103int_port_event;
309
310 static void
311 attach_mn103int_regs (struct hw *me,
312                       struct mn103int *controller)
313 {
314   int i;
315   if (hw_find_property (me, "reg") == NULL)
316     hw_abort (me, "Missing \"reg\" property");
317   for (i = 0; i < NR_BLOCKS; i++)
318     {
319       unsigned_word attach_address;
320       int attach_space;
321       unsigned attach_size;
322       reg_property_spec reg;
323       if (!hw_find_reg_array_property (me, "reg", i, &reg))
324         hw_abort (me, "\"reg\" property must contain three addr/size entries");
325       hw_unit_address_to_attach_address (hw_parent (me),
326                                          &reg.address,
327                                          &attach_space,
328                                          &attach_address,
329                                          me);
330       controller->block[i].base = attach_address;
331       hw_unit_size_to_attach_size (hw_parent (me),
332                                    &reg.size,
333                                    &attach_size, me);
334       controller->block[i].bound = attach_address + (attach_size - 1);
335       hw_attach_address (hw_parent (me),
336                          0,
337                          attach_space, attach_address, attach_size,
338                          me);
339     }
340 }
341
342 static void
343 mn103int_finish (struct hw *me)
344 {
345   int gid;
346   struct mn103int *controller;
347
348   controller = HW_ZALLOC (me, struct mn103int);
349   set_hw_data (me, controller);
350   set_hw_io_read_buffer (me, mn103int_io_read_buffer);
351   set_hw_io_write_buffer (me, mn103int_io_write_buffer);
352   set_hw_ports (me, mn103int_ports);
353   set_hw_port_event (me, mn103int_port_event);
354
355   /* Attach ourself to our parent bus */
356   attach_mn103int_regs (me, controller);
357
358   /* Initialize all the groups according to their default configuration */
359   for (gid = 0; gid < NR_GROUPS; gid++)
360     {
361       struct mn103int_group *group = &controller->group[gid];
362       group->enable = 0xf;
363       group->trigger = NEGATIVE_EDGE;
364       group->gid = gid;
365       if (FIRST_NMI_GROUP <= gid && gid <= LAST_NMI_GROUP)
366         {
367           group->type = NMI_GROUP;
368         }
369       else if (FIRST_LEVEL_GROUP <= gid && gid <= LAST_LEVEL_GROUP)
370         {
371           group->type = LEVEL_GROUP;
372         }
373       else
374         hw_abort (me, "internal error - unknown group id");
375     }
376 }
377
378
379
380 /* Perform the nasty work of figuring out which of the interrupt
381    groups should have its interrupt delivered. */
382
383 static int
384 find_highest_interrupt_group (struct hw *me,
385                               struct mn103int *controller)
386 {
387   int gid;
388   int selected;
389
390   /* FIRST_NMI_GROUP (group zero) is used as a special default value
391      when searching for an interrupt group.*/
392   selected = FIRST_NMI_GROUP; 
393   controller->group[FIRST_NMI_GROUP].level = 7;
394   
395   for (gid = FIRST_LEVEL_GROUP; gid <= LAST_LEVEL_GROUP; gid++)
396     {
397       struct mn103int_group *group = &controller->group[gid];
398       if ((group->request & group->enable) != 0)
399         {
400           /* Remember, lower level, higher priority.  */
401           if (group->level < controller->group[selected].level)
402             {
403               selected = gid;
404             }
405         }
406     }
407   return selected;
408 }
409
410
411 /* Notify the processor of an interrupt level update */
412
413 static void
414 push_interrupt_level (struct hw *me,
415                       struct mn103int *controller)
416 {
417   int selected = find_highest_interrupt_group (me, controller);
418   int level = controller->group[selected].level;
419   HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
420   hw_port_event (me, LEVEL_PORT, level);
421 }
422
423
424 /* An event arrives on an interrupt port */
425
426 static void
427 mn103int_port_event (struct hw *me,
428                      int my_port,
429                      struct hw *source,
430                      int source_port,
431                      int level)
432 {
433   struct mn103int *controller = hw_data (me);
434
435   switch (my_port)
436     {
437
438     case ACK_PORT:
439       {
440         int selected = find_highest_interrupt_group (me, controller);
441         if (controller->group[selected].level != level)
442           hw_abort (me, "botched level synchronisation");
443         controller->interrupt_accepted_group = selected;        
444         HW_TRACE ((me, "port-event port=ack level=%d - selected=%d",
445                    level, selected));
446         break;
447       }
448
449     default:
450       {
451         int gid;
452         int iid;
453         struct mn103int_group *group;
454         unsigned interrupt;
455         if (my_port > NR_G_PORTS)
456           hw_abort (me, "Event on unknown port %d", my_port);
457
458         /* map the port onto an interrupt group */
459         gid = (my_port % NR_G_PORTS) / 4;
460         group = &controller->group[gid];
461         iid = (my_port % 4);
462         interrupt = 1 << iid;
463
464         /* update our cached input */
465         if (level)
466           group->input |= interrupt;
467         else
468           group->input &= ~interrupt;
469
470         /* update the request bits */
471         switch (group->trigger)
472           {
473           case ACTIVE_LOW:
474           case ACTIVE_HIGH:
475             if (level)
476               group->request |= interrupt;
477             break;
478           case NEGATIVE_EDGE:
479           case POSITIVE_EDGE:
480             group->request |= interrupt;
481           }
482
483         /* force a corresponding output */
484         switch (group->type)
485           {
486
487           case NMI_GROUP:
488             {
489               /* for NMI's the event is the trigger */
490               HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI",
491                          my_port, gid, iid));
492               if ((group->request & group->enable) != 0)
493                 {
494                   HW_TRACE ((me, "port-out NMI"));
495                   hw_port_event (me, NMI_PORT, 1);
496                 }
497               break;
498             }
499               
500           case LEVEL_GROUP:
501             {
502               /* if an interrupt is now pending */
503               HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
504                          my_port, gid, iid));
505               push_interrupt_level (me, controller);
506               break;
507             }
508           }
509         break;
510       }
511
512     }
513 }
514
515 /* Read/write to to an ICR (group control register) */
516
517 static struct mn103int_group *
518 decode_group (struct hw *me,
519               struct mn103int *controller,
520               unsigned_word base,
521               unsigned_word *offset)
522 {
523   int gid = (base / 4) % NR_GROUPS;
524   *offset = (base % 4);
525   return &controller->group[gid];
526 }
527
528 static unsigned8
529 read_icr (struct hw *me,
530           struct mn103int *controller,
531           unsigned_word base)
532 {
533   unsigned_word offset;
534   struct mn103int_group *group = decode_group (me, controller, base, &offset);
535   unsigned8 val = 0;
536   switch (group->type)
537     {
538
539     case NMI_GROUP:
540       switch (offset)
541         {
542         case 0:
543           val = INSERT_ID (group->request);
544           HW_TRACE ((me, "read-icr group=%d:0 nmi 0x%02x",
545                      group->gid, val));
546           break;
547         default:
548           break;
549         }
550       break;
551
552     case LEVEL_GROUP:
553       switch (offset)
554         {
555         case 0:
556           val = (INSERT_IR (group->request)
557                  | INSERT_ID (group->request & group->enable));
558           HW_TRACE ((me, "read-icr group=%d:0 level 0x%02x",
559                      group->gid, val));
560           break;
561         case 1:
562           val = (INSERT_LV (group->level)
563                  | INSERT_IE (group->enable));
564           HW_TRACE ((me, "read-icr level-%d:1 level 0x%02x",
565                      group->gid, val));
566           break;
567         }
568       break;
569
570     default:
571       break;
572
573     }
574
575   return val;
576 }
577
578 static void
579 write_icr (struct hw *me,
580            struct mn103int *controller,
581            unsigned_word base,
582            unsigned8 val)
583 {
584   unsigned_word offset;
585   struct mn103int_group *group = decode_group (me, controller, base, &offset);
586   switch (group->type)
587     {
588
589     case NMI_GROUP:
590       switch (offset)
591         {
592         case 0:
593           HW_TRACE ((me, "write-icr group=%d:0 nmi 0x%02x",
594                      group->gid, val));
595           group->request &= ~EXTRACT_ID (val);
596           break;
597         default:
598           break;
599         }
600       break;
601
602     case LEVEL_GROUP:
603       switch (offset)
604         {
605         case 0: /* request/detect */
606           /* Clear any ID bits and then set them according to IR */
607           HW_TRACE ((me, "write-icr group=%d:0 level 0x%02x %x:%x:%x",
608                      group->gid, val,
609                      group->request, EXTRACT_IR (val), EXTRACT_ID (val)));
610           group->request =
611             ((EXTRACT_IR (val) & EXTRACT_ID (val))
612              | (EXTRACT_IR (val) & group->request)
613              | (~EXTRACT_IR (val) & ~EXTRACT_ID (val) & group->request));
614           break;
615         case 1: /* level/enable */
616           HW_TRACE ((me, "write-icr group=%d:1 level 0x%02x",
617                      group->gid, val));
618           group->level = EXTRACT_LV (val);
619           group->enable = EXTRACT_IE (val);
620           break;
621         default:
622           /* ignore */
623           break;
624         }
625       push_interrupt_level (me, controller);
626       break;
627
628     default:
629       break;
630
631     }
632 }
633
634
635 /* Read the IAGR (Interrupt accepted group register) */
636
637 static unsigned8
638 read_iagr (struct hw *me,
639            struct mn103int *controller,
640            unsigned_word offset)
641 {
642   unsigned8 val;
643   switch (offset)
644     {
645     case 0:
646       {
647         if (!(controller->group[controller->interrupt_accepted_group].request
648               & controller->group[controller->interrupt_accepted_group].enable))
649           {
650             /* oops, lost the request */
651             val = 0;
652             HW_TRACE ((me, "read-iagr:0 lost-0"));
653           }
654         else
655           {
656             val = (controller->interrupt_accepted_group << 2);
657             HW_TRACE ((me, "read-iagr:0 %d", (int) val));
658           }
659         break;
660       }
661     case 1:
662       val = 0;
663       HW_TRACE ((me, "read-iagr:1 %d", (int) val));
664       break;
665     default:
666       val = 0;
667       HW_TRACE ((me, "read-iagr 0x%08lx bad offset", (long) offset));
668       break;
669     }
670   return val;
671 }
672
673
674 /* Reads/writes to the EXTMD (external interrupt trigger configuration
675    register) */
676
677 static struct mn103int_group *
678 external_group (struct mn103int *controller,
679                 unsigned_word offset)
680 {
681   switch (offset)
682     {
683     case 0:
684       return &controller->group[16];
685     case 1:
686       return &controller->group[20];
687     default:
688       return NULL;
689     }
690 }
691
692 static unsigned8
693 read_extmd (struct hw *me,
694             struct mn103int *controller,
695             unsigned_word offset)
696 {
697   int gid;
698   unsigned8 val = 0;
699   struct mn103int_group *group = external_group (controller, offset);
700   if (group != NULL)
701     {
702       for (gid = 0; gid < 4; gid++)
703         {
704           val |= (group[gid].trigger << (gid * 2));
705         }
706     }
707   HW_TRACE ((me, "read-extmd 0x%02lx", (long) val));
708   return val;
709 }
710
711 static void
712 write_extmd (struct hw *me,
713              struct mn103int *controller,
714              unsigned_word offset,
715              unsigned8 val)
716 {
717   int gid;
718   struct mn103int_group *group = external_group (controller, offset);
719   if (group != NULL)
720     {
721       for (gid = 0; gid < 4; gid++)
722         {
723           group[gid].trigger = (val >> (gid * 2)) & 0x3;
724           /* MAYBE: interrupts already pending? */
725         }
726     }
727   HW_TRACE ((me, "write-extmd 0x%02lx", (long) val));
728 }
729
730
731 /* generic read/write */
732
733 static int
734 decode_addr (struct hw *me,
735              struct mn103int *controller,
736              unsigned_word address,
737              unsigned_word *offset)
738 {
739   int i;
740   for (i = 0; i < NR_BLOCKS; i++)
741     {
742       if (address >= controller->block[i].base
743           && address <= controller->block[i].bound)
744         {
745           *offset = address - controller->block[i].base;
746           return i;
747         }
748     }
749   hw_abort (me, "bad address");
750   return -1;
751 }
752
753 static unsigned
754 mn103int_io_read_buffer (struct hw *me,
755                          void *dest,
756                          int space,
757                          unsigned_word base,
758                          unsigned nr_bytes)
759 {
760   struct mn103int *controller = hw_data (me);
761   unsigned8 *buf = dest;
762   unsigned byte;
763   /* HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); */
764   for (byte = 0; byte < nr_bytes; byte++)
765     {
766       unsigned_word address = base + byte;
767       unsigned_word offset;
768       switch (decode_addr (me, controller, address, &offset))
769         {
770         case ICR_BLOCK:
771           buf[byte] = read_icr (me, controller, offset);
772           break;
773         case IAGR_BLOCK:
774           buf[byte] = read_iagr (me, controller, offset);
775           break;
776         case EXTMD_BLOCK:
777           buf[byte] = read_extmd (me, controller, offset);
778           break;
779         default:
780           hw_abort (me, "bad switch");
781         }
782     }
783   return nr_bytes;
784 }     
785
786 static unsigned
787 mn103int_io_write_buffer (struct hw *me,
788                           const void *source,
789                           int space,
790                           unsigned_word base,
791                           unsigned nr_bytes)
792 {
793   struct mn103int *controller = hw_data (me);
794   const unsigned8 *buf = source;
795   unsigned byte;
796   /* HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes)); */
797   for (byte = 0; byte < nr_bytes; byte++)
798     {
799       unsigned_word address = base + byte;
800       unsigned_word offset;
801       switch (decode_addr (me, controller, address, &offset))
802         {
803         case ICR_BLOCK:
804           write_icr (me, controller, offset, buf[byte]);
805           break;
806         case IAGR_BLOCK:
807           /* not allowed */
808           break;
809         case EXTMD_BLOCK:
810           write_extmd (me, controller, offset, buf[byte]);
811           break;
812         default:
813           hw_abort (me, "bad switch");
814         }
815     }
816   return nr_bytes;
817 }     
818
819
820 const struct hw_device_descriptor dv_mn103int_descriptor[] = {
821   { "mn103int", mn103int_finish, },
822   { NULL },
823 };