summaryrefslogtreecommitdiffabout
path: root/gammu/emb/common/device/serial/ser_djg.c
Unidiff
Diffstat (limited to 'gammu/emb/common/device/serial/ser_djg.c') (more/less context) (show whitespace changes)
-rw-r--r--gammu/emb/common/device/serial/ser_djg.c395
1 files changed, 382 insertions, 13 deletions
diff --git a/gammu/emb/common/device/serial/ser_djg.c b/gammu/emb/common/device/serial/ser_djg.c
index 2524187..609deb8 100644
--- a/gammu/emb/common/device/serial/ser_djg.c
+++ b/gammu/emb/common/device/serial/ser_djg.c
@@ -1,3 +1,8 @@
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 */
1 6
2#include "../../gsmstate.h" 7#include "../../gsmstate.h"
3 8
@@ -5,55 +10,419 @@
5#ifdef DJGPP 10#ifdef DJGPP
6 11
7#include "../../gsmcomon.h" 12#include "../../gsmcomon.h"
13#include "../../misc/coding/coding.h"
8#include "ser_djg.h" 14#include "ser_djg.h"
9 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
27extern unsigned short __djgpp_ds_alias;
28extern void SVAsyncProtISR(void);
29
30static unsigned char SVAsyncStatus=0;
31
32static void lock_interrupt_memory(void);
33static 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
39static unsigned char VectorNum; /* Vector Number */
40static unsigned char EnableIRQ; /* Mask to enable 8259 IRQ */
41static unsigned char DisableIRQ; /* Mask to disable 8259 IRQ */
42static _go32_dpmi_seginfo ProtVector; /* Old Protmode Vector */
43static _go32_dpmi_seginfo info; /* New Protmode Vector */
44
45/* Register Addresses for the UART */
46static unsigned short Port; /* Port Base Address */
47unsigned short THR; /* Transmitter Holding Register */
48unsigned short RDR; /* Reciever Data Register */
49unsigned short BRDL; /* Baud Rate Divisor, Low byte */
50unsigned short BRDH; /* Baud Rate Divisor, High Byte */
51unsigned short IER; /* Interupt Enable Register */
52unsigned short IIR; /* Interupt Identification Register */
53unsigned short FCR; /* FIFO Control Register */
54unsigned short LCR; /* Line Control Register */
55unsigned short MCR; /* Modem Control Register */
56unsigned short LSR; /* Line Status Register */
57unsigned short MSR; /* Modem Status Register */
58unsigned 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. */
65static 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 */
85static 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 */
98void 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 */
121void SVAsyncHand(unsigned int Hand)
122{
123 outportb(MCR, Hand | 0x08); /* Keep interrupt enable ON */
124}
125
126static 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
167static 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
10static GSM_Error serial_close(GSM_StateMachine *s) 196static GSM_Error serial_close(GSM_StateMachine *s)
11{ 197{
12 GSM_Device_SerialData *d = &s->Device.Data.Serial; 198 SVAsyncStop();
13 199
14 return ERR_NOTIMPLEMENTED; 200 return ERR_NONE;
15} 201}
16 202
17static GSM_Error serial_open (GSM_StateMachine *s) 203static GSM_Error serial_open (GSM_StateMachine *s)
18{ 204{
19 GSM_Device_SerialData *d = &s->Device.Data.Serial; 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 (mystrncasecmp(s->CurrentConfig->Device,"com1:",0)) {
211 Port = 0x03F8;
212 VectorNum = 0x0C;
213 EnableIRQ = 0xEF;
214 DisableIRQ = 0x10;
215 } else if (mystrncasecmp(s->CurrentConfig->Device,"com2:",0)) {
216 Port = 0x02F8;
217 VectorNum = 0x0B;
218 EnableIRQ = 0xF7;
219 DisableIRQ = 0x08;
220 } else if (mystrncasecmp(s->CurrentConfig->Device,"com3:",0)) {
221 Port = 0x03E8;
222 VectorNum = 0x0C;
223 EnableIRQ = 0xEF;
224 DisableIRQ = 0x10;
225 } else if (mystrncasecmp(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);
20 312
21 return ERR_NOTIMPLEMENTED; 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;
22} 357}
23 358
24static GSM_Error serial_setparity(GSM_StateMachine *s, bool parity) 359static GSM_Error serial_setparity(GSM_StateMachine *s, bool parity)
25{ 360{
26 GSM_Device_SerialData *d = &s->Device.Data.Serial; 361 GSM_Device_SerialData *d = &s->Device.Data.Serial;
27 362
28 return ERR_NOTIMPLEMENTED; 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;
29} 372}
30 373
31static GSM_Error serial_setdtrrts(GSM_StateMachine *s, bool dtr, bool rts) 374static GSM_Error serial_setdtrrts(GSM_StateMachine *s, bool dtr, bool rts)
32{ 375{
33 GSM_Device_SerialData *d = &s->Device.Data.Serial; 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 }
34 385
35 return ERR_NOTIMPLEMENTED; 386 return ERR_NONE;
36} 387}
37 388
38static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed) 389static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed)
39{ 390{
40 GSM_Device_SerialData *d = &s->Device.Data.Serial; 391 GSM_Device_SerialData *d = &s->Device.Data.Serial;
41 392
42 return ERR_NOTIMPLEMENTED; 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;
43} 402}
44 403
45static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes) 404static int serial_read(GSM_StateMachine *s, char *buf, size_t nbytes)
46{ 405{
47 GSM_Device_SerialData *d = &s->Device.Data.Serial; 406 if(RecTail == RecHead) return 0;
407
408 disable();
409 buf[0] = RecBuffer[RecTail++];
410 if(RecTail >= BufSize) RecTail = 0;
411 enable();
48 412
49 return 0; 413 return 1;
50} 414}
51 415
52static int serial_write(GSM_StateMachine *s, void *buf, size_t nbytes) 416static int serial_write(GSM_StateMachine *s, char *buf, size_t nbytes)
53{ 417{
54 GSM_Device_SerialData *d = &s->Device.Data.Serial; 418 int i;
419
420 for (i=0;i<nbytes;i++) {
421 while(~inportb(LSR) & 0x20);
422 outportb(THR, buf[i]);
423 }
55 424
56 return 0; 425 return i;
57} 426}
58 427
59GSM_Device_Functions SerialDevice = { 428GSM_Device_Functions SerialDevice = {