root/arch/alpha/kernel/irq.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. disable_irq
  2. enable_irq
  3. get_irq_list
  4. ack_irq
  5. mask_irq
  6. unmask_irq
  7. request_irq
  8. free_irq
  9. handle_nmi
  10. unexpected_irq
  11. handle_irq
  12. device_interrupt
  13. isa_device_interrupt
  14. cabriolet_and_eb66p_device_interrupt
  15. eb66_and_eb64p_device_interrupt
  16. srm_device_interrupt
  17. probe_irq_on
  18. probe_irq_off
  19. machine_check
  20. do_entInt
  21. init_IRQ

   1 /*
   2  *      linux/arch/alpha/kernel/irq.c
   3  *
   4  *      Copyright (C) 1995 Linus Torvalds
   5  *
   6  * This file contains the code used by various IRQ handling routines:
   7  * asking for different IRQ's should be done through these routines
   8  * instead of just grabbing them. Thus setups with different IRQ numbers
   9  * shouldn't result in any weird surprises, and installing new handlers
  10  * should be easier.
  11  */
  12 
  13 #include <linux/config.h>
  14 #include <linux/ptrace.h>
  15 #include <linux/errno.h>
  16 #include <linux/kernel_stat.h>
  17 #include <linux/signal.h>
  18 #include <linux/sched.h>
  19 #include <linux/interrupt.h>
  20 
  21 #include <asm/system.h>
  22 #include <asm/io.h>
  23 #include <asm/irq.h>
  24 #include <asm/bitops.h>
  25 #include <asm/dma.h>
  26 
  27 static unsigned char cache_21 = 0xff;
  28 static unsigned char cache_A1 = 0xff;
  29 
  30 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  31   static unsigned char cache_804 = 0xef;
  32   static unsigned char cache_805 = 0xff;
  33   static unsigned char cache_806 = 0xff;
  34 # define NUM_IRQS       33
  35 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
  36   static unsigned char cache_26 = 0xdf;
  37   static unsigned char cache_27 = 0xff;
  38 # define NUM_IRQS       32
  39 #else
  40 # define NUM_IRQS       16
  41 #endif
  42 
  43 void disable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  44 {
  45         unsigned long flags;
  46         unsigned char mask;
  47 
  48         save_flags(flags);
  49         cli();
  50         mask = 1 << (irq_nr & 7);
  51 
  52         if (irq_nr < 8) {
  53                 cache_21 |= mask;
  54                 outb(cache_21,0x21);
  55         } else if (irq_nr < 16) {
  56                 cache_A1 |= mask;
  57                 outb(cache_A1,0xA1);
  58 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  59         } else if (irq_nr < 24) {
  60                 cache_804 |= mask;
  61                 outb(cache_804, 0x804);
  62         } else if (irq_nr < 32) {
  63                 cache_805 |= mask;
  64                 outb(cache_805, 0x805);
  65         } else {
  66                 cache_806 |= mask;
  67                 outb(cache_806, 0x806);
  68 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) 
  69         } else if (irq_nr < 24) {
  70                 cache_26 |= mask;
  71                 outb(cache_26, 0x26);
  72         } else {
  73                 cache_27 |= mask;
  74                 outb(cache_27, 0x27);
  75 #endif
  76         }
  77         restore_flags(flags);
  78 }
  79 
  80 void enable_irq(unsigned int irq_nr)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         unsigned long flags;
  83         unsigned char mask;
  84 
  85         mask = ~(1 << (irq_nr & 7));
  86         save_flags(flags);
  87         cli();
  88 
  89         if (irq_nr < 8) {
  90                 cache_21 &= mask;
  91                 outb(cache_21,0x21);
  92         } else if (irq_nr < 16) {
  93                 cache_A1 &= mask;
  94                 outb(cache_A1,0xA1);
  95 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
  96         } else if (irq_nr < 24) {
  97                 cache_804 &= mask;
  98                 outb(cache_804, 0x804);
  99         } else if (irq_nr < 32) {
 100                 cache_805 &= mask;
 101                 outb(cache_805, 0x805);
 102         } else {
 103                 cache_806 &= mask;
 104                 outb(cache_806, 0x806);
 105 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 106         } else if if (irq_nr < 24) {
 107                 cache_26 &= mask;
 108                 outb(cache_26, 0x26);
 109         } else {
 110                 cache_27 &= mask;
 111                 outb(cache_27, 0x27);
 112 #endif
 113         }
 114         restore_flags(flags);
 115 }
 116 
 117 /*
 118  * Initial irq handlers.
 119  */
 120 struct irqaction {
 121         void (*handler)(int, struct pt_regs *);
 122         unsigned long flags;
 123         unsigned long mask;
 124         const char *name;
 125 };
 126 
 127 static struct irqaction irq_action[NUM_IRQS];
 128 
 129 int get_irq_list(char *buf)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131         int i, len = 0;
 132         struct irqaction * action = irq_action;
 133 
 134         for (i = 0 ; i < NUM_IRQS ; i++, action++) {
 135                 if (!action->handler)
 136                         continue;
 137                 len += sprintf(buf+len, "%2d: %8d %c %s\n",
 138                         i, kstat.interrupts[i],
 139                         (action->flags & SA_INTERRUPT) ? '+' : ' ',
 140                         action->name);
 141         }
 142         return len;
 143 }
 144 
 145 static inline void ack_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147         if (irq < 16) {
 148                 /* ACK the interrupt making it the lowest priority */
 149                 /*  First the slave .. */
 150                 if (irq > 7) {
 151                         outb(0xE0 | (irq - 8), 0xa0);
 152                         irq = 2;
 153                 }
 154                 /* .. then the master */
 155                 outb(0xE0 | irq, 0x20);
 156         }
 157 }
 158 
 159 static inline void mask_irq(int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         unsigned char mask;
 162 
 163         mask = 1 << (irq & 7);
 164         if (irq < 8) {
 165                 cache_21 |= mask;
 166                 outb(cache_21, 0x21);
 167         } else if (irq < 16) {
 168                 cache_A1 |= mask;
 169                 outb(cache_A1, 0xA1);
 170 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 171         } else if (irq < 24) {
 172                 cache_804 |= mask;
 173                 outb(cache_804, 0x804);
 174         } else if (irq < 32) {
 175                 cache_805 |= mask;
 176                 outb(cache_805, 0x805);
 177         } else {
 178                 cache_806 |= mask;
 179                 outb(cache_806, 0x806);
 180 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
 181         } else if (irq < 24) {
 182                 cache_26 |= mask;
 183                 outb(cache_26, 0x26);
 184         } else {
 185                 cache_27 |= mask;
 186                 outb(cache_27, 0x27);
 187 #endif
 188         }
 189 }
 190 
 191 static inline void unmask_irq(unsigned long irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 192 {
 193         unsigned char mask = ~(1 << (irq & 7));
 194 
 195         if (irq < 8) {
 196                 cache_21 &= mask;
 197                 outb(cache_21, 0x21);
 198         } else if (irq < 16) {
 199                 cache_A1 &= mask;
 200                 outb(cache_A1, 0xA1);
 201 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 202         } else if (irq < 24) {
 203                 cache_804 &= mask;
 204                 outb(cache_804, 0x804);
 205         } else if (irq < 32) {
 206                 cache_805 &= mask;
 207                 outb(cache_805, 0x805);
 208         } else {
 209                 cache_806 &= mask;
 210                 outb(cache_806, 0x806);
 211 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB66P)
 212         } else if (irq < 24) {
 213                 cache_26 &= mask;
 214                 outb(cache_26, 0x26);
 215         } else {
 216                 cache_27 &= mask;
 217                 outb(cache_27, 0x27);
 218 #endif
 219         }
 220 }
 221 
 222 int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
     /* [previous][next][first][last][top][bottom][index][help] */
 223         unsigned long irqflags, const char * devname)
 224 {
 225         struct irqaction * action;
 226         unsigned long flags;
 227 
 228         if (irq >= NUM_IRQS)
 229                 return -EINVAL;
 230         action = irq + irq_action;
 231         if (action->handler)
 232                 return -EBUSY;
 233         if (!handler)
 234                 return -EINVAL;
 235         save_flags(flags);
 236         cli();
 237         action->handler = handler;
 238         action->flags = irqflags;
 239         action->mask = 0;
 240         action->name = devname;
 241         enable_irq(irq);
 242         if (irq >= 8 && irq < 16) {
 243                 enable_irq(2);  /* ensure cascade is enabled too */
 244         }
 245         restore_flags(flags);
 246         return 0;
 247 }
 248 
 249 void free_irq(unsigned int irq)
     /* [previous][next][first][last][top][bottom][index][help] */
 250 {
 251         struct irqaction * action = irq + irq_action;
 252         unsigned long flags;
 253 
 254         if (irq >= NUM_IRQS) {
 255                 printk("Trying to free IRQ%d\n", irq);
 256                 return;
 257         }
 258         if (!action->handler) {
 259                 printk("Trying to free free IRQ%d\n", irq);
 260                 return;
 261         }
 262         save_flags(flags);
 263         cli();
 264         mask_irq(irq);
 265         action->handler = NULL;
 266         action->flags = 0;
 267         action->mask = 0;
 268         action->name = NULL;
 269         restore_flags(flags);
 270 }
 271 
 272 static inline void handle_nmi(struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274         printk("Whee.. NMI received. Probable hardware error\n");
 275         printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
 276 }
 277 
 278 static void unexpected_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280         int i;
 281 
 282         printk("IO device interrupt, irq = %d\n", irq);
 283         printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 284         printk("Expecting: ");
 285         for (i = 0; i < 16; i++)
 286                 if (irq_action[i].handler)
 287                         printk("[%s:%d] ", irq_action[i].name, i);
 288         printk("\n");
 289         printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
 290                 inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
 291         outb(0x0c, 0x3fc);
 292         outb(0x0c, 0x2fc);
 293         outb(0,0x61);
 294         outb(0,0x461);
 295 }
 296 
 297 static inline void handle_irq(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299         struct irqaction * action = irq + irq_action;
 300 
 301         kstat.interrupts[irq]++;
 302         if (!action->handler) {
 303                 unexpected_irq(irq, regs);
 304                 return;
 305         }
 306         action->handler(irq, regs);
 307 }
 308 
 309 static inline void device_interrupt(int irq, int ack, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 310 {
 311         struct irqaction * action;
 312 
 313         if ((unsigned) irq > NUM_IRQS) {
 314                 printk("device_interrupt: unexpected interrupt %d\n", irq);
 315                 return;
 316         }
 317 
 318         kstat.interrupts[irq]++;
 319         action = irq_action + irq;
 320         /* quick interrupts get executed with no extra overhead */
 321         if (action->flags & SA_INTERRUPT) {
 322                 action->handler(irq, regs);
 323                 ack_irq(ack);
 324                 return;
 325         }
 326         /*
 327          * For normal interrupts, we mask it out, and then ACK it.
 328          * This way another (more timing-critical) interrupt can
 329          * come through while we're doing this one.
 330          *
 331          * Note! A irq without a handler gets masked and acked, but
 332          * never unmasked. The autoirq stuff depends on this (it looks
 333          * at the masks before and after doing the probing).
 334          */
 335         mask_irq(ack);
 336         ack_irq(ack);
 337         if (!action->handler)
 338                 return;
 339         action->handler(irq, regs);
 340         unmask_irq(ack);
 341 }
 342 
 343 /*
 344  * Handle ISA interrupt via the PICs.
 345  */
 346 static inline void isa_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 347                                         struct pt_regs * regs)
 348 {
 349         unsigned long pic;
 350         int j;
 351         /* 
 352          *  The first read of gives you *all* interrupting lines.
 353          *  Therefore, read the mask register and and out those lines
 354          *  not enabled.  Note that some documentation has 21 and a1 
 355          *  write only.  This is not true.
 356          */
 357         pic = inb(0x20) | (inb(0xA0) << 8);     /* read isr */
 358         pic &= ~((cache_A1 << 8) | cache_21);   /* apply mask */
 359         pic &= 0xFFFB;                          /* mask out cascade */
 360 
 361         while (pic) {
 362                 j = ffz(~pic);
 363                 pic &= pic - 1;
 364                 device_interrupt(j, j, regs);
 365         }
 366 }
 367 
 368 static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 369                                                         struct pt_regs * regs)
 370 {
 371         unsigned long pld;
 372         unsigned int i;
 373         unsigned long flags;
 374 
 375         save_flags(flags);
 376         cli();
 377 
 378         /* read the interrupt summary registers */
 379         pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
 380 
 381         /*
 382          * Now for every possible bit set, work through them and call
 383          * the appropriate interrupt handler.
 384          */
 385         while (pld) {
 386                 i = ffz(~pld);
 387                 pld &= pld - 1; /* clear least bit set */
 388                 if (i == 4) {
 389                         isa_device_interrupt(vector, regs);
 390                 } else {
 391                         device_interrupt(16 + i, 16 + i, regs);
 392                 }
 393         }
 394         restore_flags(flags);
 395 }
 396 
 397 static inline void eb66_and_eb64p_device_interrupt(unsigned long vector,
     /* [previous][next][first][last][top][bottom][index][help] */
 398                                                    struct pt_regs * regs)
 399 {
 400         unsigned long pld;
 401         unsigned int i;
 402         unsigned long flags;
 403 
 404         save_flags(flags);
 405         cli();
 406 
 407         /* read the interrupt summary registers */
 408         pld = inb(0x26) | (inb(0x27) << 8);
 409         /*
 410          * Now, for every possible bit set, work through
 411          * them and call the appropriate interrupt handler.
 412          */
 413         while (pld) {
 414                 i = ffz(~pld);
 415                 pld &= pld - 1; /* clear least bit set */
 416 
 417                 if (i == 5) {
 418                         isa_device_interrupt(vector, regs);
 419                 } else {
 420                         device_interrupt(16 + i, 16 + i, regs);
 421                 }
 422         }
 423         restore_flags(flags);
 424 }
 425 
 426 /*
 427  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
 428  * 0x9X0 for the local motherboard interrupts..
 429  *
 430  *      0x660 - NMI
 431  *
 432  *      0x800 - IRQ0  interval timer (not used, as we use the RTC timer)
 433  *      0x810 - IRQ1  line printer (duh..)
 434  *      0x860 - IRQ6  floppy disk
 435  *      0x8E0 - IRQ14 SCSI controller
 436  *
 437  *      0x900 - COM1
 438  *      0x920 - COM2
 439  *      0x980 - keyboard
 440  *      0x990 - mouse
 441  *
 442  * PCI-based systems are more sane: they don't have the local
 443  * interrupts at all, and have only normal PCI interrupts from
 444  * devices.  Happily it's easy enough to do a sane mapping from the
 445  * Jensen..  Note that this means that we may have to do a hardware
 446  * "ack" to a different interrupt than we report to the rest of the
 447  * world.
 448  */
 449 static inline void srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 450 {
 451         int irq, ack;
 452         struct irqaction * action;
 453 
 454         ack = irq = (vector - 0x800) >> 4;
 455 
 456 #ifdef CONFIG_ALPHA_JENSEN
 457         switch (vector) {
 458               case 0x660: handle_nmi(regs); return;
 459                 /* local device interrupts: */
 460               case 0x900: handle_irq(4, regs); return;  /* com1 -> irq 4 */
 461               case 0x920: handle_irq(3, regs); return;  /* com2 -> irq 3 */
 462               case 0x980: handle_irq(1, regs); return;  /* kbd -> irq 1 */
 463               case 0x990: handle_irq(9, regs); return;  /* mouse -> irq 9 */
 464               default:
 465                 if (vector > 0x900) {
 466                         printk("Unknown local interrupt %lx\n", vector);
 467                 }
 468         }
 469         /* irq1 is supposed to be the keyboard, silly Jensen (is this really needed??) */
 470         if (irq == 1)
 471                 irq = 7;
 472 #endif /* CONFIG_ALPHA_JENSEN */
 473 
 474         device_interrupt(irq, ack, regs);
 475 }
 476 
 477 #if NUM_IRQS > 64
 478 #  error Number of irqs limited to 64 due to interrupt-probing.
 479 #endif
 480 
 481 /*
 482  * Start listening for interrupts..
 483  */
 484 unsigned long probe_irq_on(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 485 {
 486         unsigned long irqs = 0, irqmask;
 487         unsigned long delay;
 488         unsigned int i;
 489 
 490         for (i = NUM_IRQS - 1; i > 0; i--) {
 491                 if (!irq_action[i].handler) {
 492                         enable_irq(i);
 493                         irqs |= (1 << i);
 494                 }
 495         }
 496 
 497         /* wait for spurious interrupts to mask themselves out again */
 498         for (delay = jiffies + HZ/10; delay > jiffies; )
 499                 /* about 100 ms delay */;
 500         
 501         /* now filter out any obviously spurious interrupts */
 502         irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21;
 503 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 504         irqmask |= ((((unsigned long)cache_804)<<16) |
 505                     (((unsigned long)cache_805)<<24) |
 506                     (((unsigned long)cache_806)<<24));
 507 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 508         irqmask |= ((((unsigned long)cache_26)<<16) |
 509                     (((unsigned long)cache_27)<<24);
 510 #endif
 511         irqs &= ~irqmask;
 512         return irqs;
 513 }
 514 
 515 /*
 516  * Get the result of the IRQ probe.. A negative result means that
 517  * we have several candidates (but we return the lowest-numbered
 518  * one).
 519  */
 520 int probe_irq_off(unsigned long irqs)
     /* [previous][next][first][last][top][bottom][index][help] */
 521 {
 522         unsigned long irqmask;
 523         int i;
 524         
 525         irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 526 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 527         irqmask |= ((((unsigned long)cache_804)<<16) |
 528                     (((unsigned long)cache_805)<<24) |
 529                     (((unsigned long)cache_806)<<24));
 530 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 531         irqmask |= ((((unsigned long)cache_26)<<16) |
 532                     (((unsigned long)cache_27)<<24);
 533 #endif
 534         irqs &= irqmask;
 535         if (!irqs)
 536                 return 0;
 537         i = ffz(~irqs);
 538         if (irqs != (1UL << i))
 539                 i = -i;
 540         return i;
 541 }
 542 
 543 static void machine_check(unsigned long vector, unsigned long la, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 544 {
 545 #if defined(CONFIG_ALPHA_LCA)
 546         extern void lca_machine_check (unsigned long vector, unsigned long la,
 547                                        struct pt_regs *regs);
 548         lca_machine_check(vector, la, regs);
 549 #elif defined(CONFIG_ALPHA_APECS)
 550         extern void apecs_machine_check(unsigned long vector, unsigned long la,
 551                                         struct pt_regs * regs);
 552         apecs_machine_check(vector, la, regs);
 553 #else
 554         printk("Machine check\n");
 555 #endif
 556 }
 557 
 558 asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 559         unsigned long a3, unsigned long a4, unsigned long a5,
 560         struct pt_regs regs)
 561 {
 562         switch (type) {
 563                 case 0:
 564                         printk("Interprocessor interrupt? You must be kidding\n");
 565                         break;
 566                 case 1:
 567                         /* timer interrupt.. */
 568                         handle_irq(0, &regs);
 569                         return;
 570                 case 2:
 571                         machine_check(vector, la_ptr, &regs);
 572                         break;
 573                 case 3:
 574 #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME)
 575                         srm_device_interrupt(vector, &regs);
 576 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 577                         cabriolet_and_eb66p_device_interrupt(vector, &regs);
 578 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 579                         eb66_and_eb64p_device_interrupt(vector, &regs);
 580 #endif
 581                         return;
 582                 case 4:
 583                         printk("Performance counter interrupt\n");
 584                         break;;
 585                 default:
 586                         printk("Hardware intr %ld %lx? Huh?\n", type, vector);
 587         }
 588         printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
 589 }
 590 
 591 extern asmlinkage void entInt(void);
 592 
 593 void init_IRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 594 {
 595         wrent(entInt, 0);
 596         dma_outb(0, DMA1_RESET_REG);
 597         dma_outb(0, DMA2_RESET_REG);
 598         dma_outb(0, DMA1_CLR_MASK_REG);
 599         dma_outb(0, DMA2_CLR_MASK_REG);
 600 #if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P)
 601         outb(cache_804, 0x804);
 602         outb(cache_805, 0x805);
 603         outb(cache_806, 0x806);
 604 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 605         outb(cache_26, 0x26);
 606         outb(cache_27, 0x27);
 607 #endif
 608 }

/* [previous][next][first][last][top][bottom][index][help] */