home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CPPCOM17.ZIP / UART.CPP < prev    next >
C/C++ Source or Header  |  1991-02-27  |  10KB  |  470 lines

  1. /***************************************************************************
  2. These C++ classes are copyright 1990, by William Herrera.
  3. All those who put this code or its derivatives in a commercial product MUST
  4. mention this copyright in their documentation for users of the products in
  5. which this code or its derivative classes are used.  Otherwise, this code
  6. may be freely distributed and freely used for any purpose.
  7. ***************************************************************************/
  8.  
  9. // File uart.cpp, class definitions for the uart class.
  10. // By William Herrera.
  11.  
  12. // See your modem manual (I used MultiTech's) or the IBM Technical
  13. // reference manual for more information on the 8250 UART used in the PC.
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17.  
  18.  
  19. #include "uart.hpp"
  20.  
  21. // Note:  the parameters below are the defaults used by MultiTech.
  22. // If you have problems with using your modem, look up the maximum
  23. // speed it uses and its addresses and vectors and adjust accordingly.
  24.  
  25. static const long default_baud_rate = 38400L;
  26.  
  27. unsigned int uart::io_address[NUM_PORTS] = { 0x3F8, 0x2F8, 0x2E8, 0x3E8 };
  28.  
  29. int uart::portvector_num[NUM_PORTS] = { 0xC, 0xB, 0xB, 0xC };
  30.  
  31. char uart::intmaskbit[NUM_PORTS] = { 0x10, 0x08, 0x08, 0x10 };
  32.  
  33. char uart::old_intmask[NUM_PORTS] = { 0, 0 , 0 , 0 };
  34. char uart::old_MCR[NUM_PORTS] = { 0, 0 , 0 , 0 };
  35. char uart::old_IER[NUM_PORTS] = { 0, 0, 0, 0 };
  36.  
  37. #ifdef __TURBOC__
  38. DRIVER uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
  39. #else ifdef __ZTC__
  40. void far * uart::old_driver[NUM_PORTS] = { NULL, NULL, NULL, NULL };
  41. #endif
  42.  
  43. uart::uart() { ; }
  44.  
  45. uart::~uart() { ; }
  46.  
  47. // the function below allows us to set the parameters for a given
  48. // set of hadware used by the UART, especially for ports above COM2.
  49. // Note this should be done BEFORE allocating a class instance.
  50.  
  51. void uart::SetPortAddresses(int portnum, unsigned int io_add,
  52.          int portvec, char imask)
  53. {
  54.     int indx = portnum - 1;
  55.     if(
  56.         (indx < 0) || (indx > NUM_PORTS - 1) || 
  57.             (old_driver[indx] != NULL) )
  58.     {
  59.         fputs("uart::SetPortAdressses() cannot set port requested.\n", 
  60.                 stderr);
  61.     }
  62.     else
  63.     {
  64.         io_address[indx] = io_add;
  65.         portvector_num[indx] = portvec;
  66.         intmaskbit[indx] = imask;
  67.     }
  68. }
  69.  
  70. // the following function sets up the PC for interrupt-driven serial
  71. // communications through the UART.  Returns 0 for success, -1 for
  72. // port disallowed, -2 for uart interrupts not resettable.
  73. int uart::RegisterDriver(int portnum, DRIVER driv)
  74. {
  75.     int retval;
  76.     if(
  77.         (portnum < 1) || (portnum > NUM_PORTS) || 
  78.             (old_driver[portnum - 1] != NULL) )
  79.     {
  80.         fputs("uart::RegisterDriver() cannot set port requested.\n", 
  81.                 stderr);
  82.         retval = -1;
  83.     }
  84.     else
  85.     {
  86.         disable();
  87.         // Hardware interrupts off til we change the settings.
  88.         // Make sure DLAB of LSR is 0 to allow access to IER and MCR.
  89.         SetLCR_DLAB(false);
  90.         // Save old IER and MCR.
  91.         old_IER[portnum -1] = GetIER();
  92.         old_MCR[portnum- 1] = GetMCR();
  93.         // Then check the UART for accessibility.
  94.         SetIER(0);
  95.         if(GetIER() != 0)
  96.         {
  97.             fputs("uart error:  unable to reset IER\n", stderr);
  98.             retval = -2;
  99.         }
  100.         else
  101.         {
  102.             // save the old interrupt mask.
  103.             old_intmask[portnum - 1] = inportb(0x21);
  104.                 
  105.             // reset vector to point to our handler.
  106. #ifdef __TURBOC__
  107.             old_driver[portnum - 1] = getvect(portvector_num[portnum - 1]);
  108.             setvect(portvector_num[portnum - 1], driv);
  109. #else ifdef __ZTC__
  110.             unsigned int iseg, ioff;
  111.             int_getvector(portvector_num[portnum - 1], &ioff, &iseg);
  112.             old_driver[portnum - 1] = MK_FP(iseg, ioff);
  113.             int_intercept(portvector_num[portnum - 1], driv, 0);
  114. #endif
  115.             SetMCR(9);    // turn on DTR and interrupts by modem (1|8).
  116.             SetIER(13);    // turn on data ready, line, modem ints (1|4|8).
  117.  
  118.             // Now enable controller for serial port interrupts.
  119.             outportb( 0x21, (inportb(0x21) & ~(intmaskbit[portnum - 1])) );
  120.  
  121.             // set speed to predefined default_baud_rate.
  122.             SetSpeed(default_baud_rate);
  123.             // Set port to default parameters of 8 data, 1 stop, no parity.
  124.             SetParity(NOPAR);
  125.             SetWordLength(8);
  126.             SetStopBits(1);
  127.  
  128.             retval = 0;
  129.         }
  130.         enable();
  131.     }
  132.     return retval;
  133. }
  134.  
  135. // This function resets the interrupt controller and UART and 
  136. // generally cleans up after the RegisterDriver function.
  137. // Returns 0 on success, -1 on port not restorable.
  138. int uart::RestoreDriver(int portnum)
  139. {
  140.     int retval;
  141.     if( (portnum < 1) || (portnum > NUM_PORTS) || 
  142.             (old_driver[portnum - 1] == NULL) )
  143.     {
  144.         fputs("UART Error:  Cannot restore port.\n", stderr);
  145.         retval = -1;
  146.     }
  147.     else 
  148.     {
  149.         // reset the interrupt vector.
  150.         disable();
  151. #ifdef __TURBOC__
  152.         setvect(portvector_num[portnum - 1], old_driver[portnum - 1]);
  153. #else ifdef __ZTC__
  154.         int_restore(portvector_num[portnum - 1]);    
  155. #endif
  156.         // reset the i8259 mask to its original state.
  157.         outportb(0x21, old_intmask[portnum - 1]);
  158.         // reset UART registers.
  159.         SetIER(old_IER[portnum -1]);    
  160.         SetMCR(old_MCR[portnum - 1]);
  161.         enable();
  162.         old_driver[portnum - 1] = NULL;
  163.         retval = 0;
  164.     }
  165.     return retval;
  166. }
  167.  
  168. char uart::GetLCR()
  169. {
  170.     return inportb(LCR());
  171. }
  172.  
  173. char uart::GetDLL()
  174. {
  175.     return inportb(DLL());
  176. }
  177.  
  178. char uart::GetDLM()
  179. {     
  180.     return inportb(DLM());
  181. }
  182.  
  183. char uart::GetLSR()
  184. {      
  185.     return inportb(LSR());
  186. }
  187.  
  188. char uart::GetMCR()
  189. {   
  190.     return inportb(MCR());
  191. }
  192.  
  193. char uart::GetMSR()
  194. {    
  195.     return inportb(MSR());
  196. }
  197.  
  198. char uart::GetRBR()
  199. {    
  200.     return inportb(RBR());
  201. }
  202.  
  203. char uart::GetIER()
  204. {    
  205.     return inportb(IER());
  206. }
  207.  
  208. char uart::GetIIR()
  209. {
  210.     return inportb(IIR());
  211. }
  212.  
  213. boolean uart::GetLSR_THRE()
  214. {
  215.     return (GetLSR() & 32) ? true : false;
  216. }
  217.  
  218. void uart::SetLCR(char byte)
  219. {
  220.     outportb(LCR(), byte);
  221. }
  222.  
  223. void uart::SetDLL(char byte)
  224. {
  225.     outportb(DLL(), byte);
  226. }
  227.  
  228. void uart::SetDLM(char byte)
  229. {
  230.     outportb(DLM(), byte);
  231. }
  232.  
  233. void uart::SetLSR(char byte)
  234. {
  235.     outportb(LSR(), byte);
  236. }
  237.  
  238. void uart::SetMCR(char byte)
  239. {
  240.     outportb(MCR(), byte);
  241. }
  242.  
  243. void uart::SetMSR(char byte)
  244. {
  245.     outportb(MSR(), byte);
  246. }
  247.  
  248. void uart::SetTHR(char byte)
  249. {
  250.     outportb(THR(), byte);
  251. }
  252.  
  253. void uart::SetIER(char byte)
  254. {
  255.     outportb(IER(), byte);
  256. }
  257.  
  258. void uart::SetIER_Recieve(boolean bit)
  259. {
  260.     SetIER( (bit) ? GetIER() | 1 : GetIER() & (~1) );
  261. }
  262.  
  263. void uart::SetIER_Transmit(boolean bit)
  264. {
  265.     SetIER( (bit) ? GetIER() | 2 : GetIER() & (~2) );
  266. }
  267.  
  268. void uart::SetIER_Line(boolean bit)
  269. {
  270.     SetIER( (bit) ? GetIER() | 4 : GetIER() & (~4) );
  271. }
  272.  
  273. void uart::SetIER_Modem(boolean bit)
  274. {
  275.     SetIER( (bit) ? GetIER() | 8 : GetIER() & (~8) );
  276. }
  277.  
  278. void uart::SetLCR_DLAB(boolean bit)
  279. {
  280.     SetLCR( (bit) ? GetLCR() | 128 : GetLCR() & (~128) );
  281. }
  282.  
  283. void uart::SetLSR_DR(boolean bit)
  284. {
  285.     SetLSR( (bit) ? GetLSR() | 1 : GetLSR() & (~1) );
  286. }
  287.  
  288. void uart::SetBaudRate(long speed)
  289. {
  290.     long divisor = 115200L / speed;
  291.     char lsb = divisor & 0xFF;
  292.     char msb = (divisor >> 8) & 0xFF;
  293.     SetLCR_DLAB(true);        
  294.     SetDLL(lsb);
  295.     SetDLM(msb);
  296.     SetLCR_DLAB(false);
  297. }
  298.         
  299. long uart::GetBaudRate()
  300. {
  301.     SetLCR_DLAB(true);
  302.     int lsb = GetDLL() & 0xFF;    
  303.     int msb = GetDLM() & 0xFF;
  304.     SetLCR_DLAB(false);
  305.     return ( 115200L / (((long)msb << 8) + (long)lsb) );
  306. }
  307.  
  308. void uart::SetParity(parity_t p)
  309. {
  310.     SetLCR( (GetLCR() & 0xC7) | p);
  311. }    
  312.  
  313. parity_t uart::GetParity()
  314. {
  315.     return (parity_t)(GetLCR() & 0x38);
  316. }
  317.  
  318. void uart::SetWordLength(int len)
  319. {
  320.     SetLCR( (GetLCR() & 0xFC) | ((len - 5) & 3) );
  321. }
  322.  
  323. int uart::GetWordLength()
  324. {
  325.     return (GetLCR() & 3) + 5;
  326. }
  327.  
  328. void uart::SetStopBits(int num)
  329. {
  330.     SetLCR( (GetLCR() & 0xFB) | ((num == 1) ? 0 : 4) );
  331. }
  332.  
  333. int uart::GetStopBits()
  334. {
  335.     return (GetLCR() & 4) ? 1 : 2;
  336. }
  337.  
  338. void uart::SetBreak()
  339. {
  340.     SetLCR(GetLCR() | 64);
  341. }
  342.  
  343. void uart::StopBreak()
  344. {
  345.     SetLCR(GetLCR() & (~64));
  346. }
  347.  
  348. void uart::Pause(int msec)
  349. {
  350.     // assumes the PC BIOS tick is 18.2 per second, or
  351.     // 55 msec per tick.
  352.     // DO NOT call this from an interrupt driver that uses the clock!
  353.     union REGS regs;
  354.     regs.x.ax = 0;
  355.     int86(0x1A, ®s, ®s);
  356.     int startcount = regs.x.dx;
  357.     int endcount = startcount + (msec / 55);
  358.     int i = startcount;
  359.     while(i < endcount && i >= startcount)
  360.     {
  361.         regs.x.ax = 0;
  362.         int86(0x1A, ®s, ®s);
  363.         i = regs.x.dx;
  364.     }
  365. }
  366.  
  367. void uart::Break(int msec)
  368. {
  369.     // assumes the PC BIOS tick is 18.2 per second, or
  370.     // 55 msec per tick.
  371.     // DO NOT call this from an interrupt driver that uses the clock!
  372.     SetBreak();
  373.     Pause(msec);
  374.     StopBreak();
  375. }
  376.  
  377. void uart::SetCTS(boolean bit)
  378. {
  379.     SetMSR( (bit) ? (GetMSR() | 16) : (GetMSR() & (~16)) );
  380. }
  381.  
  382. void uart::SetDSR(boolean bit)
  383. {
  384.     SetMSR( (bit) ? (GetMSR() | 32) : (GetMSR() & (~32)) );
  385. }
  386.  
  387. boolean uart::CarrierPresent()
  388. {
  389.     // actually tests RLSD, bit 7 of MSR.
  390.     return (GetMSR() & 128) ? true : false;
  391. }
  392.  
  393. void uart::SetDTR(boolean bit)
  394. {
  395.     SetMCR( (bit) ? (GetMCR() | 1) : (GetMCR() & (~1)) );
  396. }
  397.  
  398. boolean uart::GetDTR()
  399. {
  400.     return (GetMCR() & 1) ? true : false;
  401. }
  402.  
  403. com_interrupt_t uart::GetIntrType()
  404. {
  405.     int type = (int)GetIIR() & 0xFF;
  406.     if(type & 1)
  407.         return NONE_PENDING;
  408.     int r;
  409.     switch(type)
  410.     {
  411.         case 0:
  412.             r = GetMSR();
  413.             if(r & 4)
  414.                 return RING;
  415.             else if (r & 128)
  416.                 return CARRIER;
  417.             else 
  418.                 return NO_CARRIER;
  419.         case 2:
  420.             r = GetLSR();
  421.             if(r & 32)   // THRE
  422.                 return TRANSMIT_READY;
  423.             else 
  424.                 return TRANSMIT_FALSE_ALARM;
  425.         case 4:
  426.             return RECEIVE_READY;
  427.         case 6:
  428.             r = GetLSR();
  429.             if(r & 2)    // 
  430.                 return OVERRUN_ERROR;
  431.             else if(r & 4)
  432.                 return PARITY_ERROR;
  433.             else if(r & 8)
  434.                 return FRAMING_ERROR;
  435.             else if(r & 16)
  436.                 return BREAK_RECEIVED;
  437.             else 
  438.                 return UNKNOWN_ERROR;
  439.         default : 
  440.             return UNKNOWN_ERROR; 
  441.     }
  442. }
  443.  
  444.  
  445. int uart::GetChar()
  446. {
  447.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  448.     return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;
  449. }
  450.  
  451. void uart:: SendChar(char ch)
  452. {   
  453.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  454.     // this method works only if there is room in the transmit register.
  455.     outportb(THR(), ch);
  456. }
  457.  
  458. void uart::TransmitChar(char ch)
  459. {
  460.     // similar to last one -- allows other to be overloaded separately
  461.     outportb(THR(), ch);
  462. }
  463.  
  464. int uart::ReceiveChar()
  465. {
  466.     // similar to GetChar() -- allows other to be overloaded separately
  467.     // note: for this method to work, SetLCR_DLAB(false) must be called.
  468.     return (GetLSR() & 1) ? ( (int)inportb(RBR()) & 0x00FF ) : -1;    
  469. }
  470.