Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:45

0001 /*
0002  *  SMC1 raw console serial I/O.
0003  *
0004  *  This driver is an example of `POLLING' or `INTERRUPT' I/O.
0005  *
0006  *  To run with interrupt-driven I/O, ensure m360_smc1_interrupt
0007  *  is set before calling the initialization routine.
0008  */
0009 
0010 /*
0011  * Copyright (c) 1996 Eric Norum <eric@norum.ca>
0012  *
0013  * COPYRIGHT (c) 1989-1999.
0014  * On-Line Applications Research Corporation (OAR).
0015  *
0016  * The license and distribution terms for this file may be
0017  * found in the file LICENSE in this distribution or at
0018  * http://www.rtems.org/license/LICENSE.
0019  */
0020 
0021 #include <termios.h>
0022 #include <bsp.h>
0023 #include <rtems/libio.h>
0024 #include <rtems/console.h>
0025 #include <rtems/termiostypes.h>
0026 #include <rtems/m68k/m68360.h>
0027 
0028 /*
0029  * Declare clock speed -- may be overwritten by downloader or debugger
0030  */
0031 int m360_clock_rate  = 25000000;
0032 
0033 /*
0034  * Interrupt-driven input buffer
0035  * Declare console baud rate -- may also be overwritten
0036  */
0037 int console_baud_rate = 9600;
0038 
0039 /*
0040  */
0041 #define RXBUFSIZE  16
0042 
0043 /*
0044  * Interrupt-driven callback
0045  */
0046 static int m360_smc1_interrupt = 1;
0047 static void *smc1ttyp;
0048 
0049 /*
0050  * I/O buffers and pointers to buffer descriptors
0051  */
0052 static volatile char rxBuf[RXBUFSIZE];
0053 static volatile m360BufferDescriptor_t *smcRxBd, *smcTxBd;
0054 
0055 /*
0056  * Device-specific routines
0057  */
0058 
0059 /*
0060  * Compute baud-rate-generator configuration register value
0061  */
0062 static int
0063 smc1BRGC (int baud)
0064 {
0065   int divisor;
0066   int div16 = 0;
0067 
0068   divisor = ((m360_clock_rate / 16) + (baud / 2)) / baud;
0069   if (divisor > 4096) {
0070     div16 = 1;
0071     divisor = (divisor + 8) / 16;
0072   }
0073   return M360_BRG_EN | M360_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
0074 }
0075 
0076 /*
0077  * Hardware-dependent portion of tcsetattr().
0078  */
0079 static int
0080 smc1SetAttributes (int minor, const struct termios *t)
0081 {
0082   int baud;
0083 
0084   baud = rtems_termios_baud_to_number(t->c_ospeed);
0085   if (baud > 0)
0086     m360.brgc1 = smc1BRGC (baud);
0087   return 0;
0088 }
0089 
0090 /*
0091  * Interrupt handler
0092  */
0093 static rtems_isr
0094 smc1InterruptHandler (rtems_vector_number v)
0095 {
0096   /*
0097    * Buffer received?
0098    */
0099   if (m360.smc1.smce & 0x1) {
0100     m360.smc1.smce = 0x1;
0101     while ((smcRxBd->status & M360_BD_EMPTY) == 0) {
0102       rtems_termios_enqueue_raw_characters (smc1ttyp,
0103               (char *)smcRxBd->buffer,
0104               smcRxBd->length);
0105       smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
0106     }
0107   }
0108 
0109   /*
0110    * Buffer transmitted?
0111    */
0112   if (m360.smc1.smce & 0x2) {
0113     m360.smc1.smce = 0x2;
0114     if ((smcTxBd->status & M360_BD_READY) == 0)
0115       rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
0116   }
0117   m360.cisr = 1UL << 4;  /* Clear SMC1 interrupt-in-service bit */
0118 }
0119 
0120 static int
0121 smc1Initialize (int major, int minor, void *arg)
0122 {
0123   /*
0124    * Allocate buffer descriptors
0125    */
0126   smcRxBd = M360AllocateBufferDescriptors (1);
0127   smcTxBd = M360AllocateBufferDescriptors (1);
0128 
0129   /*
0130    * Configure port B pins to enable SMTXD1 and SMRXD1 pins
0131    */
0132   m360.pbpar |=  0xC0;
0133   m360.pbdir &= ~0xC0;
0134   m360.pbodr &= ~0xC0;
0135 
0136   /*
0137    * Set up BRG1 (9,600 baud)
0138    */
0139   m360.brgc1 = M360_BRG_RST;
0140   m360.brgc1 = smc1BRGC (console_baud_rate);
0141 
0142   /*
0143    * Put SMC1 in NMSI mode, connect SMC1 to BRG1
0144    */
0145   m360.simode |= M360_SI_SMC1_BRG1;
0146 
0147   /*
0148    * Set up SMC1 parameter RAM common to all protocols
0149    */
0150   m360.smc1p.rbase = (char *)smcRxBd - (char *)&m360;
0151   m360.smc1p.tbase = (char *)smcTxBd - (char *)&m360;
0152   m360.smc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
0153   m360.smc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
0154   if (m360_smc1_interrupt)
0155     m360.smc1p.mrblr = RXBUFSIZE;
0156   else
0157     m360.smc1p.mrblr = 1;
0158 
0159   /*
0160    * Set up SMC1 parameter RAM UART-specific parameters
0161    */
0162   m360.smc1p.un.uart.max_idl = 10;
0163   m360.smc1p.un.uart.brklen = 0;
0164   m360.smc1p.un.uart.brkec = 0;
0165   m360.smc1p.un.uart.brkcr = 0;
0166 
0167   /*
0168    * Set up the Receive Buffer Descriptor
0169    */
0170   smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
0171   smcRxBd->length = 0;
0172   smcRxBd->buffer = rxBuf;
0173 
0174   /*
0175    * Setup the Transmit Buffer Descriptor
0176    */
0177   smcTxBd->status = M360_BD_WRAP;
0178 
0179   /*
0180    * Set up SMC1 general and protocol-specific mode registers
0181    */
0182   m360.smc1.smce = ~0;  /* Clear any pending events */
0183   m360.smc1.smcm = 0;  /* Mask all interrupt/event sources */
0184   m360.smc1.smcmr = M360_SMCMR_CLEN(9) | M360_SMCMR_SM_UART;
0185 
0186   /*
0187    * Send "Init parameters" command
0188    */
0189   M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SMC1);
0190 
0191   /*
0192    * Enable receiver and transmitter
0193    */
0194   m360.smc1.smcmr |= M360_SMCMR_TEN | M360_SMCMR_REN;
0195 
0196   if (m360_smc1_interrupt) {
0197   rtems_isr_entry old_handler;
0198 
0199   (void) rtems_interrupt_catch (smc1InterruptHandler,
0200             (m360.cicr & 0xE0) | 0x04,
0201             &old_handler);
0202   m360.smc1.smcm = 3;  /* Enable SMC1 TX and RX interrupts */
0203   m360.cimr |= 1UL << 4;  /* Enable SMC1 interrupts */
0204   }
0205 
0206   return 0;
0207 }
0208 
0209 static int
0210 smc1PollRead (int minor)
0211 {
0212   unsigned char c;
0213 
0214   if (smcRxBd->status & M360_BD_EMPTY)
0215     return -1;
0216   c = rxBuf[0];
0217   smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP;
0218   return c;
0219 }
0220 
0221 /*
0222  * Device-dependent write routine
0223  * Interrupt-driven devices:
0224  *  Begin transmission of as many characters as possible (minimum is 1).
0225  * Polling devices:
0226  *  Transmit all characters.
0227  */
0228 static ssize_t
0229 smc1InterruptWrite (int minor, const char *buf, size_t len)
0230 {
0231   if (len > 0) {
0232     smcTxBd->buffer = (char *)buf;
0233     smcTxBd->length = len;
0234     smcTxBd->status = M360_BD_READY | M360_BD_WRAP | M360_BD_INTERRUPT;
0235   }
0236 
0237   return 0;
0238 }
0239 
0240 static ssize_t
0241 smc1PollWrite (int minor, const char *buf, size_t len)
0242 {
0243   size_t retval = len;
0244   while (len--) {
0245     static char txBuf;
0246     while (smcTxBd->status & M360_BD_READY)
0247       continue;
0248     txBuf = *buf++;
0249     smcTxBd->buffer = &txBuf;
0250     smcTxBd->length = 1;
0251     smcTxBd->status = M360_BD_READY | M360_BD_WRAP;
0252   }
0253   return retval;
0254 }
0255 
0256 /*
0257  ***************
0258  * BOILERPLATE *
0259  ***************
0260  */
0261 
0262 /*
0263  * Reserve resources consumed by this driver
0264  *
0265  * NOTE: This is in another file to reduce dependencies on the minimum size.
0266  */
0267 
0268 /*
0269  * Initialize and register the device
0270  */
0271 rtems_device_driver console_initialize(
0272   rtems_device_major_number  major,
0273   rtems_device_minor_number  minor,
0274   void                      *arg
0275 )
0276 {
0277   rtems_status_code status;
0278 
0279   /*
0280    * Set up TERMIOS
0281    */
0282   rtems_termios_initialize ();
0283 
0284   /*
0285    * Register the device
0286    */
0287   status = rtems_io_register_name ("/dev/console", major, 0);
0288   if (status != RTEMS_SUCCESSFUL)
0289     rtems_fatal_error_occurred (status);
0290   return RTEMS_SUCCESSFUL;
0291 }
0292 
0293 /*
0294  * Open the device
0295  */
0296 rtems_device_driver console_open(
0297   rtems_device_major_number major,
0298   rtems_device_minor_number minor,
0299   void                    * arg
0300 )
0301 {
0302   rtems_status_code sc;
0303   static const rtems_termios_callbacks intrCallbacks = {
0304     smc1Initialize,    /* firstOpen */
0305     NULL,      /* lastClose */
0306     NULL,      /* pollRead */
0307     smc1InterruptWrite,  /* write */
0308     smc1SetAttributes,  /* setAttributes */
0309     NULL,      /* stopRemoteTx */
0310     NULL,      /* startRemoteTx */
0311     TERMIOS_IRQ_DRIVEN      /* outputUsesInterrupts */
0312   };
0313   static const rtems_termios_callbacks pollCallbacks = {
0314     smc1Initialize,    /* firstOpen */
0315     NULL,      /* lastClose */
0316     smc1PollRead,    /* pollRead */
0317     smc1PollWrite,    /* write */
0318     smc1SetAttributes,  /* setAttributes */
0319     NULL,      /* stopRemoteTx */
0320     NULL,      /* startRemoteTx */
0321     TERMIOS_POLLED      /* outputUsesInterrupts */
0322   };
0323 
0324   /*
0325    * Do generic termios initialization
0326    */
0327   if (m360_smc1_interrupt) {
0328     rtems_libio_open_close_args_t *args = arg;
0329 
0330     sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
0331     smc1ttyp = args->iop->data1;
0332   }
0333   else {
0334     sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
0335   }
0336   return sc;
0337 }
0338 
0339 /*
0340  * Close the device
0341  */
0342 rtems_device_driver console_close(
0343   rtems_device_major_number major,
0344   rtems_device_minor_number minor,
0345   void                    * arg
0346 )
0347 {
0348   return rtems_termios_close (arg);
0349 }
0350 
0351 /*
0352  * Read from the device
0353  */
0354 rtems_device_driver console_read(
0355   rtems_device_major_number major,
0356   rtems_device_minor_number minor,
0357   void                    * arg
0358 )
0359 {
0360   return rtems_termios_read (arg);
0361 }
0362 
0363 /*
0364  * Write to the device
0365  */
0366 rtems_device_driver console_write(
0367   rtems_device_major_number major,
0368   rtems_device_minor_number minor,
0369   void                    * arg
0370 )
0371 {
0372   return rtems_termios_write (arg);
0373 }
0374 
0375 /*
0376  * Handle ioctl request.
0377  */
0378 rtems_device_driver console_control(
0379   rtems_device_major_number major,
0380   rtems_device_minor_number minor,
0381   void                    * arg
0382 )
0383 {
0384   return rtems_termios_ioctl (arg);
0385 }