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