This commit was generated by cvs2svn to track changes on a CVS vendor
[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           if (group->level > controller->group[selected].level)
401             {
402               selected = gid;
403             }
404         }
405     }
406   return selected;
407 }
408
409
410 /* Notify the processor of an interrupt level update */
411
412 static void
413 push_interrupt_level (struct hw *me,
414                       struct mn103int *controller)
415 {
416   int selected = find_highest_interrupt_group (me, controller);
417   int level = controller->group[selected].level;
418   HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
419   hw_port_event (me, LEVEL_PORT, level, NULL, NULL_CIA);
420 }
421
422
423 /* An event arrives on an interrupt port */
424
425 static void
426 mn103int_port_event (struct hw *me,
427                      int my_port,
428                      struct hw *source,
429                      int source_port,
430                      int level,
431                      sim_cpu *processor,
432                      sim_cia cia)
433 {
434   struct mn103int *controller = hw_data (me);
435
436   switch (my_port)
437     {
438
439     case ACK_PORT:
440       {
441         int selected = find_highest_interrupt_group (me, controller);
442         if (controller->group[selected].level != level)
443           hw_abort (me, "botched level synchronisation");
444         controller->interrupt_accepted_group = selected;        
445         HW_TRACE ((me, "port-event port=ack level=%d - selected=%d",
446                    level, selected));
447         break;
448       }
449
450     default:
451       {
452         int gid;
453         int iid;
454         struct mn103int_group *group;
455         unsigned interrupt;
456         if (my_port > NR_G_PORTS)
457           hw_abort (me, "Event on unknown port %d", my_port);
458
459         /* map the port onto an interrupt group */
460         gid = (my_port % NR_G_PORTS) / 4;
461         group = &controller->group[gid];
462         iid = (my_port % 4);
463         interrupt = 1 << iid;
464
465         /* update our cached input */
466         if (level)
467           group->input |= interrupt;
468         else
469           group->input &= ~interrupt;
470
471         /* update the request bits */
472         switch (group->trigger)
473           {
474           case ACTIVE_LOW:
475           case ACTIVE_HIGH:
476             if (level)
477               group->request |= interrupt;
478             break;
479           case NEGATIVE_EDGE:
480           case POSITIVE_EDGE:
481             group->request |= interrupt;
482           }
483
484         /* force a corresponding output */
485         switch (group->type)
486           {
487
488           case NMI_GROUP:
489             {
490               /* for NMI's the event is the trigger */
491               HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI",
492                          my_port, gid, iid));
493               if ((group->request & group->enable) != 0)
494                 {
495                   HW_TRACE ((me, "port-out NMI"));
496                   hw_port_event (me, NMI_PORT, 1, NULL, NULL_CIA);
497                 }
498               break;
499             }
500               
501           case LEVEL_GROUP:
502             {
503               /* if an interrupt is now pending */
504               HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
505                          my_port, gid, iid));
506               push_interrupt_level (me, controller);
507               break;
508             }
509           }
510         break;
511       }
512
513     }
514 }
515
516 /* Read/write to to an ICR (group control register) */
517
518 static struct mn103int_group *
519 decode_group (struct hw *me,
520               struct mn103int *controller,
521               unsigned_word base,
522               unsigned_word *offset)
523 {
524   int gid = (base / 8) % NR_GROUPS;
525   *offset = (base % 8);
526   return &controller->group[gid];
527 }
528
529 static unsigned8
530 read_icr (struct hw *me,
531           struct mn103int *controller,
532           unsigned_word base)
533 {
534   unsigned_word offset;
535   struct mn103int_group *group = decode_group (me, controller, base, &offset);
536   unsigned8 val = 0;
537   switch (group->type)
538     {
539
540     case NMI_GROUP:
541       switch (offset)
542         {
543         case 0:
544           val = INSERT_ID (group->request);
545           HW_TRACE ((me, "read-icr group=%d nmi 0x%02x",
546                      group->gid, val));
547           break;
548         default:
549           break;
550         }
551       break;
552
553     case LEVEL_GROUP:
554       switch (offset)
555         {
556         case 0:
557           val = (INSERT_IR (group->request)
558                  | INSERT_ID (group->request & group->enable));
559           HW_TRACE ((me, "read-icr group=%d level 0 0x%02x",
560                      group->gid, val));
561           break;
562         case 1:
563           val = (INSERT_LV (group->level)
564                  | INSERT_IE (group->enable));
565           HW_TRACE ((me, "read-icr level-%d level 1 0x%02x",
566                      group->gid, val));
567           break;
568         }
569       break;
570
571     default:
572       break;
573
574     }
575
576   return val;
577 }
578
579 static void
580 write_icr (struct hw *me,
581            struct mn103int *controller,
582            unsigned_word base,
583            unsigned8 val)
584 {
585   unsigned_word offset;
586   struct mn103int_group *group = decode_group (me, controller, base, &offset);
587   switch (group->type)
588     {
589
590     case NMI_GROUP:
591       switch (offset)
592         {
593         case 0:
594           HW_TRACE ((me, "write-icr group=%d nmi 0x%02x",
595                      group->gid, val));
596           group->request &= ~EXTRACT_ID (val);
597           break;
598         default:
599           break;
600         }
601       break;
602
603     case LEVEL_GROUP:
604       switch (offset)
605         {
606         case 0: /* request/detect */
607           /* Clear any ID bits and then set them according to IR */
608           HW_TRACE ((me, "write-icr group=%d level 0 0x%02x",
609                      group->gid, val));
610           group->request &= EXTRACT_ID (val);
611           group->request |= EXTRACT_IR (val) & EXTRACT_ID (val);
612           break;
613         case 1: /* level/enable */
614           HW_TRACE ((me, "write-icr group=%d level 1 0x%02x",
615                      group->gid, val));
616           group->level = EXTRACT_LV (val);
617           group->enable = EXTRACT_IE (val);
618           break;
619         default:
620           /* ignore */
621           break;
622         }
623       push_interrupt_level (me, controller);
624       break;
625
626     default:
627       break;
628
629     }
630 }
631
632
633 /* Read the IAGR (Interrupt accepted group register) */
634
635 static unsigned8
636 read_iagr (struct hw *me,
637            struct mn103int *controller,
638            unsigned_word offset)
639 {
640   unsigned8 val;
641   switch (offset)
642     {
643     case 0:
644       {
645         val = (controller->interrupt_accepted_group << 2);
646         if (!(controller->group[val].request
647               & controller->group[val].enable))
648           /* oops, lost the request */
649           val = 0;
650         HW_TRACE ((me, "read-iagr %d", (int) val));
651         break;
652       }
653     default:
654       val = 0;
655       HW_TRACE ((me, "read-iagr 0x%08lx bad offset", (long) offset));
656       break;
657     }
658   return val;
659 }
660
661
662 /* Reads/writes to the EXTMD (external interrupt trigger configuration
663    register) */
664
665 static struct mn103int_group *
666 external_group (struct mn103int *controller,
667                 unsigned_word offset)
668 {
669   switch (offset)
670     {
671     case 0:
672       return &controller->group[16];
673     case 1:
674       return &controller->group[20];
675     default:
676       return NULL;
677     }
678 }
679
680 static unsigned8
681 read_extmd (struct hw *me,
682             struct mn103int *controller,
683             unsigned_word offset)
684 {
685   int gid;
686   unsigned8 val = 0;
687   struct mn103int_group *group = external_group (controller, offset);
688   if (group != NULL)
689     {
690       for (gid = 0; gid < 4; gid++)
691         {
692           val |= (group[gid].trigger << (gid * 2));
693         }
694     }
695   HW_TRACE ((me, "read-extmd 0x%02lx", (long) val));
696   return val;
697 }
698
699 static void
700 write_extmd (struct hw *me,
701              struct mn103int *controller,
702              unsigned_word offset,
703              unsigned8 val)
704 {
705   int gid;
706   struct mn103int_group *group = external_group (controller, offset);
707   if (group != NULL)
708     {
709       for (gid = 0; gid < 4; gid++)
710         {
711           group[gid].trigger = (val >> (gid * 2)) & 0x3;
712           /* MAYBE: interrupts already pending? */
713         }
714     }
715   HW_TRACE ((me, "write-extmd 0x%02lx", (long) val));
716 }
717
718
719 /* generic read/write */
720
721 static int
722 decode_addr (struct hw *me,
723              struct mn103int *controller,
724              unsigned_word address,
725              unsigned_word *offset)
726 {
727   int i;
728   for (i = 0; i < NR_BLOCKS; i++)
729     {
730       if (address >= controller->block[i].base
731           && address <= controller->block[i].bound)
732         {
733           *offset = address - controller->block[i].base;
734           return i;
735         }
736     }
737   hw_abort (me, "bad address");
738   return -1;
739 }
740
741 static unsigned
742 mn103int_io_read_buffer (struct hw *me,
743                          void *dest,
744                          int space,
745                          unsigned_word base,
746                          unsigned nr_bytes,
747                          sim_cpu *processor,
748                          sim_cia cia)
749 {
750   struct mn103int *controller = hw_data (me);
751   unsigned8 *buf = dest;
752   unsigned byte;
753   HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes));
754   for (byte = 0; byte < nr_bytes; byte++)
755     {
756       unsigned_word address = base + byte;
757       unsigned_word offset;
758       switch (decode_addr (me, controller, address, &offset))
759         {
760         case ICR_BLOCK:
761           buf[byte] = read_icr (me, controller, offset);
762           break;
763         case IAGR_BLOCK:
764           buf[byte] = read_iagr (me, controller, offset);
765           break;
766         case EXTMD_BLOCK:
767           buf[byte] = read_extmd (me, controller, offset);
768           break;
769         default:
770           hw_abort (me, "bad switch");
771         }
772     }
773   return nr_bytes;
774 }     
775
776 static unsigned
777 mn103int_io_write_buffer (struct hw *me,
778                           const void *source,
779                           int space,
780                           unsigned_word base,
781                           unsigned nr_bytes,
782                           sim_cpu *cpu,
783                           sim_cia cia)
784 {
785   struct mn103int *controller = hw_data (me);
786   const unsigned8 *buf = source;
787   unsigned byte;
788   HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
789   for (byte = 0; byte < nr_bytes; byte++)
790     {
791       unsigned_word address = base + byte;
792       unsigned_word offset;
793       switch (decode_addr (me, controller, address, &offset))
794         {
795         case ICR_BLOCK:
796           write_icr (me, controller, offset, buf[byte]);
797           break;
798         case IAGR_BLOCK:
799           /* not allowed */
800           break;
801         case EXTMD_BLOCK:
802           write_extmd (me, controller, offset, buf[byte]);
803           break;
804         default:
805           hw_abort (me, "bad switch");
806         }
807     }
808   return nr_bytes;
809 }     
810
811
812 const struct hw_device_descriptor dv_mn103int_descriptor[] = {
813   { "mn103int", mn103int_finish, },
814   { NULL },
815 };