Gammu internals  1.38.0
ser_djg.c
Go to the documentation of this file.
1 /* Some sources from SVAsync (c) 1996, 1997, Samuel Vincent
2  * 7337 Carioca Ct, Rohnert Park, Ca 94928
3  * "you may freely use it in your programs without paying me anything"
4  */
5 /* Some sources from DZCOMM */
6 
7 #include "../../gsmstate.h"
8 
9 #ifdef GSM_ENABLE_SERIALDEVICE
10 #ifdef DJGPP
11 
12 #include "../../gsmcomon.h"
13 #include "../../misc/coding/coding.h"
14 #include "ser_djg.h"
15 
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <dos.h>
20 #include <dpmi.h>
21 #include <pc.h>
22 #include <go32.h>
23 #include <sys/farptr.h>
24 #include <sys/movedata.h>
25 #include <conio.h>
26 
27 extern unsigned short __djgpp_ds_alias;
28 extern void SVAsyncProtISR(void);
29 
30 static unsigned char SVAsyncStatus=0;
31 
32 static void lock_interrupt_memory(void);
33 static void unlock_interrupt_memory(void);
34 
35 #define Ctrl8259_0 0x020 /* 8259 port */
36 #define Ctrl8259_1 0x021 /* 8259 port (Masks) */
37 #define BufSize 32768 /* Buffer Size */
38 
39 static unsigned char VectorNum; /* Vector Number */
40 static unsigned char EnableIRQ; /* Mask to enable 8259 IRQ */
41 static unsigned char DisableIRQ; /* Mask to disable 8259 IRQ */
42 static _go32_dpmi_seginfo ProtVector; /* Old Protmode Vector */
43 static _go32_dpmi_seginfo info; /* New Protmode Vector */
44 
45 /* Register Addresses for the UART */
46 static unsigned short Port; /* Port Base Address */
47 unsigned short THR; /* Transmitter Holding Register */
48 unsigned short RDR; /* Reciever Data Register */
49 unsigned short BRDL; /* Baud Rate Divisor, Low byte */
50 unsigned short BRDH; /* Baud Rate Divisor, High Byte */
51 unsigned short IER; /* Interupt Enable Register */
52 unsigned short IIR; /* Interupt Identification Register */
53 unsigned short FCR; /* FIFO Control Register */
54 unsigned short LCR; /* Line Control Register */
55 unsigned short MCR; /* Modem Control Register */
56 unsigned short LSR; /* Line Status Register */
57 unsigned short MSR; /* Modem Status Register */
58 unsigned short SCR; /* SCR Register */
59 
60 /* Data Buffer */
61 unsigned volatile char RecBuffer[BufSize] = { 0 };
62 unsigned volatile int RecHead, RecTail;
63 
64 /* This uninstalls the ISR and resets the serial port. */
65 static void SVAsyncStop(void)
66 {
67  if(!SVAsyncStatus) return;
68  SVAsyncStatus = 0;
69 
70  /***** Mask (disable) 8259 IRQ Interrupt */
71  outportb(Ctrl8259_1, (inportb(Ctrl8259_1) | DisableIRQ));
72 
73  /***** Disable 8250 interrupt */
74  outportb(LCR, (inportb(LCR) & 0x7F));
75  outportb(IER, 0);
76 
77  /***** Set bit 3 in MCR to 0 */
78  outportb(MCR, (inportb(MCR) & 0xF7));
79 
80  /***** Interrupts are disabled. Restore saved interrupt vector. */
81  _go32_dpmi_set_protected_mode_interrupt_vector(VectorNum, &ProtVector);
82 }
83 
84 /* This will empty the receive buffer */
85 static void SVAsyncClear(void)
86 {
87  disable();
88  RecHead = 0;
89  RecTail = 0;
90  enable();
91 }
92 
93 
94 /* Sets communication parameters
95  * Baud = 150, 300, 600, 1200, 2400, 4800, 9600, 19200, 28800, 38400, 57600
96  * Control = The value to place in the LCR
97  */
98 void SVAsyncSet(unsigned int Baud, unsigned int Control)
99 {
100  int divisor;
101  unsigned char divlow, divhigh;
102 
103  if (!Baud) return;
104 
105  divisor = 115200 / Baud;
106 
107  disable();
108 
109  outportb(LCR, Control | 0x80); /* Set Port Toggle to BRDL/BRDH registers */
110  divlow = divisor & 0x000000ff;
111  divhigh = (divisor >> 8) & 0x000000ff;
112  outportb(BRDL, divlow); /* Set Baud Rate */
113  outportb(BRDH, divhigh);
114 
115  outportb(LCR, Control & 0x007F); /* Set LCR and Port Toggle */
116 
117  enable();
118 }
119 
120 /* Sets various handshaking lines */
121 void SVAsyncHand(unsigned int Hand)
122 {
123  outportb(MCR, Hand | 0x08); /* Keep interrupt enable ON */
124 }
125 
126 static void lock_interrupt_memory(void)
127 {
128  int errval;
129  __dpmi_meminfo info;
130  unsigned long address;
131 
132  __dpmi_get_segment_base_address(_my_ds(), &address);
133 
134  info.address = (int) address + (int) &RDR;
135  info.size = sizeof(RDR);
136  errval = __dpmi_lock_linear_region(&info);
137  if(errval == -1) printf("Error in locking memory\n!");
138 
139  info.address = (int) address + (int) &LSR;
140  info.size = sizeof(LSR);
141  errval = __dpmi_lock_linear_region(&info);
142  if(errval == -1) printf("Error in locking memory\n!");
143 
144  info.address = (int) address + (int) &RecHead;
145  info.size = sizeof(RecHead);
146  errval = __dpmi_lock_linear_region(&info);
147  if(errval == -1) printf("Error in locking memory\n!");
148 
149  info.address = (int) address + (int) &RecBuffer;
150  info.size = sizeof(RecBuffer);
151  errval = __dpmi_lock_linear_region(&info);
152  if(errval == -1) printf("Error in locking memory\n!");
153 
154  info.address = (int) address + (int) RecBuffer;
155  info.size = BufSize;
156  errval = __dpmi_lock_linear_region(&info);
157  if(errval == -1) printf("Error in locking memory\n!");
158 
159  __dpmi_get_segment_base_address(_my_cs(), &address);
160 
161  info.address = (int) address + (int) SVAsyncProtISR;
162  info.size = 4096; /* 4096 bytes is probably overkill. */
163  errval = __dpmi_lock_linear_region(&info);
164  if(errval == -1) printf("Error in locking memory\n!");
165 }
166 
167 static void unlock_interrupt_memory(void)
168 {
169  __dpmi_meminfo info;
170  unsigned long address;
171 
172  __dpmi_get_segment_base_address(_my_ds(), &address);
173  info.address = (int) address + (int) &RDR;
174  info.size = sizeof(RDR);
175  __dpmi_unlock_linear_region(&info);
176  info.address = (int) address + (int) &LSR;
177  info.size = sizeof(LSR);
178  __dpmi_unlock_linear_region(&info);
179  info.address = (int) address + (int) &RecHead;
180  info.size = sizeof(RecHead);
181  __dpmi_unlock_linear_region(&info);
182  info.address = (int) address + (int) &RecBuffer;
183  info.size = sizeof(RecBuffer);
184  __dpmi_unlock_linear_region(&info);
185  info.address = (int) address + (int) RecBuffer;
186  info.size = BufSize;
187  __dpmi_unlock_linear_region(&info);
188 
189  __dpmi_get_segment_base_address(_my_cs(), &address);
190 
191  info.address = (int) address + (int) SVAsyncProtISR;
192  info.size = 4096; /* probably overkill */
193  __dpmi_unlock_linear_region(&info);
194 }
195 
196 static GSM_Error serial_close(GSM_StateMachine *s)
197 {
198  SVAsyncStop();
199 
200  return ERR_NONE;
201 }
202 
203 static GSM_Error serial_open (GSM_StateMachine *s)
204 {
205  GSM_Device_SerialData *d = &s->Device.Data.Serial;
206  unsigned char temp;
207  int i;
208 
209  /**** Set various things according to com port number */
210  if (strcasecmp(s->CurrentConfig->Device,"com1:") == 0) {
211  Port = 0x03F8;
212  VectorNum = 0x0C;
213  EnableIRQ = 0xEF;
214  DisableIRQ = 0x10;
215  } else if (strcasecmp(s->CurrentConfig->Device,"com2:") == 0) {
216  Port = 0x02F8;
217  VectorNum = 0x0B;
218  EnableIRQ = 0xF7;
219  DisableIRQ = 0x08;
220  } else if (strcasecmp(s->CurrentConfig->Device,"com3:") == 0) {
221  Port = 0x03E8;
222  VectorNum = 0x0C;
223  EnableIRQ = 0xEF;
224  DisableIRQ = 0x10;
225  } else if (strcasecmp(s->CurrentConfig->Device,"com4:") == 0) {
226  Port = 0x02E8;
227  VectorNum = 0x0B;
228  EnableIRQ = 0xF7;
229  DisableIRQ = 0x08;
230  } else return ERR_NOTSUPPORTED;
231 
232  /**** Compute Register locations */
233  THR = Port;
234  RDR = Port;
235  BRDL = Port;
236  BRDH = 1 + Port;
237  IER = 1 + Port;
238  IIR = 2 + Port;
239  FCR = 2 + Port;
240  LCR = 3 + Port;
241  MCR = 4 + Port;
242  LSR = 5 + Port;
243  MSR = 6 + Port;
244  SCR = 7 + Port;
245 
246  /***** Initalize Buffer */
247  SVAsyncClear();
248 
249  lock_interrupt_memory();
250  atexit(unlock_interrupt_memory);
251  /***** Set bit 3 in MCR to 0 */
252  outportb(MCR, (inportb(MCR) & 0xF7));
253 
254  /*** Save and reassign interrupt vectors */
255 
256  _go32_dpmi_get_protected_mode_interrupt_vector(VectorNum, &ProtVector);
257 
258  info.pm_offset = (int) SVAsyncProtISR;
259  info.pm_selector = _my_cs();
260  _go32_dpmi_set_protected_mode_interrupt_vector(VectorNum, &info);
261 
262  atexit(SVAsyncStop);
263 
264  /***** Enable 8259 interrupt (IRQ) line for this async adapter */
265  outportb(Ctrl8259_1, (inportb(Ctrl8259_1) & EnableIRQ));
266 
267  /***** Enable 8250 Interrupt-on-data-ready */
268  outportb(LCR, (inportb(LCR) & 0x7F));
269 
270  outportb(IER, 0);
271  if (inportb(IER)) {
272  SVAsyncStatus = 0;
273  return ERR_UNKNOWN;
274  }
275  outportb(IER, 0x01);
276 
277  /***** Clear 8250 Status and data registers */
278  do {
279  temp=inportb(RDR);
280  temp=inportb(LSR);
281  temp=inportb(MSR);
282  temp=inportb(IIR);
283  } while(!(temp & 1));
284 
285  /***** Set Bit 3 of MCR -- Enable interupts */
286  outportb(MCR, (inportb(MCR) | 0x08));
287 
288  SVAsyncStatus = 1;
289  /***** Clear Buffer Just in case */
290  SVAsyncClear();
291 
292  /* Code based on stuff from SVAsync lib.
293  * Clear UART Status and data registers
294  * setting up FIFO if possible
295  */
296  outportb(SCR, 0x55);
297  if (inportb(SCR) == 0x55) {
298  /* On the off chance that SCR is actually hardwired to 0x55,
299  * do the same check with a different value.
300  */
301  outportb(SCR, 0xAA);
302  if (inportb(SCR) == 0xAA) {
303  /* The chip is better than an 8250 - it has a scratch pad */
304  outportb(SCR, i); /* Set SCR back to what it was before */
305  inportb(SCR); /* Give slow motherboards a chance */
306 
307  /* Is there a FIFO ? - go through twice for slow motherboards */
308  outportb(FCR, 0x01);
309  i = inportb(FCR);
310  outportb(FCR, 0x01);
311  i = inportb(FCR);
312 
313  /* Some old stuff relies on this (no idea why) */
314  outportb(FCR, 0x00);
315  inportb(FCR); /* Give slow motherboards a chance */
316 
317  if ((i&0x80) == 0) {
318  smprintf(s,"UART 16450 or UART 8250 with scratch pad\n");
319  } else if ((i&0x40) == 0) {
320  smprintf(s,"UART 16550 - broken FIFO\n");
321  } else {
322  /* It's a 16450A series : try and start the FIFO.
323  * It appears that some chips need a two call protocol, but
324  * those that don't seem to work even if you do start it
325  * twice. The first call is simply to start it, the second
326  * starts it and sets an 8 byte FIFO trigger level.
327  */
328  outportb(FCR, 0x01);
329  inportb(FCR); /* Give slow motherboards a chance */
330  outportb(FCR, 0x87);
331  inportb(FCR); /* Give slow motherboards a chance */
332 
333  /* Check that the FIFO initialised */
334  if ((inportb(IIR) & 0xc0) != 0xc0) {
335  /*
336  * It didn't so we assume it isn't there but disable it to
337  * be on the safe side.
338  */
339  outportb(IIR, 0xfe);
340  inportb(IIR); /* Give slow motherboards a chance */
341  smprintf(s,"UART 16450A - FIFO disabled\n");
342  } else {
343  smprintf(s,"UART 16450A - FIFO enabled\n");
344  }
345  }
346  } else {
347  smprintf(s,"UART 8250\n");
348  }
349  }
350 
351  d->Control = BITS_8 | STOP_1;
352  d->Parity = FALSE;
353  d->Speed = 9600;
354  SVAsyncSet(d->Speed,d->Control | NO_PARITY);
355 
356  return ERR_NONE;
357 }
358 
359 static GSM_Error serial_setparity(GSM_StateMachine *s, gboolean parity)
360 {
361  GSM_Device_SerialData *d = &s->Device.Data.Serial;
362 
363  d->Parity = parity;
364 
365  if (parity) {
366  SVAsyncSet(d->Speed, d->Control | ODD_PARITY);
367  } else {
368  SVAsyncSet(d->Speed, d->Control | NO_PARITY);
369  }
370 
371  return ERR_NONE;
372 }
373 
374 static GSM_Error serial_setdtrrts(GSM_StateMachine *s, gboolean dtr, gboolean rts)
375 {
376  if (dtr && rts) {
377  SVAsyncHand(DTR | RTS);
378  } else if (dtr) {
379  SVAsyncHand(DTR);
380  } else if (rts) {
381  SVAsyncHand(RTS);
382  } else {
383  SVAsyncHand(0);
384  }
385 
386  return ERR_NONE;
387 }
388 
389 static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed)
390 {
391  GSM_Device_SerialData *d = &s->Device.Data.Serial;
392 
393  d->Speed = speed;
394 
395  if (d->Parity) {
396  SVAsyncSet(d->Speed, d->Control | ODD_PARITY);
397  } else {
398  SVAsyncSet(d->Speed, d->Control | NO_PARITY);
399  }
400 
401  return ERR_NONE;
402 }
403 
404 static int serial_read(GSM_StateMachine *s, char *buf, size_t nbytes)
405 {
406  if(RecTail == RecHead) return 0;
407 
408  disable();
409  buf[0] = RecBuffer[RecTail++];
410  if(RecTail >= BufSize) RecTail = 0;
411  enable();
412 
413  return 1;
414 }
415 
416 static int serial_write(GSM_StateMachine *s, char *buf, size_t nbytes)
417 {
418  int i;
419 
420  for (i=0;i<nbytes;i++) {
421  while(~inportb(LSR) & 0x20);
422  outportb(THR, buf[i]);
423  }
424 
425  return i;
426 }
427 
428 GSM_Device_Functions SerialDevice = {
429  serial_open,
430  serial_close,
431  serial_setparity,
432  serial_setdtrrts,
433  serial_setspeed,
434  serial_read,
435  serial_write
436 };
437 
438 #endif
439 #endif
440 
441 /* How should editor hadle tabs in this file? Add editor commands here.
442  * vim: noexpandtab sw=8 ts=8 sts=8:
443  */
GSM_Config * CurrentConfig
Definition: gsmstate.h:1415
union GSM_Device::@0 Data
GSM_Error
Definition: gammu-error.h:23
int gboolean
Definition: gammu-types.h:23
#define FALSE
Definition: gammu-types.h:25
GSM_Device Device
Definition: gsmstate.h:1429
int smprintf(GSM_StateMachine *s, const char *format,...)
Definition: debug.c:261