Diffstat (limited to 'gammu/emb/common/device/serial/ser_djg.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | gammu/emb/common/device/serial/ser_djg.c | 399 |
1 files changed, 384 insertions, 15 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,74 +1,443 @@ | |||
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 | ||
4 | #ifdef GSM_ENABLE_SERIALDEVICE | 9 | #ifdef GSM_ENABLE_SERIALDEVICE |
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 | |||
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 | |||
10 | static GSM_Error serial_close(GSM_StateMachine *s) | 196 | static 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 | ||
17 | static GSM_Error serial_open (GSM_StateMachine *s) | 203 | static 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; |
20 | 206 | unsigned char temp; | |
21 | return ERR_NOTIMPLEMENTED; | 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); | ||
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; | ||
22 | } | 357 | } |
23 | 358 | ||
24 | static GSM_Error serial_setparity(GSM_StateMachine *s, bool parity) | 359 | static 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 | ||
31 | static GSM_Error serial_setdtrrts(GSM_StateMachine *s, bool dtr, bool rts) | 374 | static 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 | ||
38 | static GSM_Error serial_setspeed(GSM_StateMachine *s, int speed) | 389 | static 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 | ||
45 | static int serial_read(GSM_StateMachine *s, void *buf, size_t nbytes) | 404 | static 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 | ||
52 | static int serial_write(GSM_StateMachine *s, void *buf, size_t nbytes) | 416 | static 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 | ||
59 | GSM_Device_Functions SerialDevice = { | 428 | GSM_Device_Functions SerialDevice = { |
60 | serial_open, | 429 | serial_open, |
61 | serial_close, | 430 | serial_close, |
62 | serial_setparity, | 431 | serial_setparity, |
63 | serial_setdtrrts, | 432 | serial_setdtrrts, |
64 | serial_setspeed, | 433 | serial_setspeed, |
65 | serial_read, | 434 | serial_read, |
66 | serial_write | 435 | serial_write |
67 | }; | 436 | }; |
68 | 437 | ||
69 | #endif | 438 | #endif |
70 | #endif | 439 | #endif |
71 | 440 | ||
72 | /* How should editor hadle tabs in this file? Add editor commands here. | 441 | /* How should editor hadle tabs in this file? Add editor commands here. |
73 | * vim: noexpandtab sw=8 ts=8 sts=8: | 442 | * vim: noexpandtab sw=8 ts=8 sts=8: |
74 | */ | 443 | */ |