~ubuntu-branches/ubuntu/feisty/sl-modem/feisty

« back to all changes in this revision

Viewing changes to modem/modem_main.c

  • Committer: Bazaar Package Importer
  • Author(s): Eduard Bloch
  • Date: 2004-09-06 18:17:31 UTC
  • Revision ID: james.westby@ubuntu.com-20040906181731-si44puez4f5pzd8s
Tags: upstream-2.9.9
ImportĀ upstreamĀ versionĀ 2.9.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 *
 
4
 *    Copyright (c) 2002, Smart Link Ltd.
 
5
 *    All rights reserved.
 
6
 *
 
7
 *    Redistribution and use in source and binary forms, with or without
 
8
 *    modification, are permitted provided that the following conditions
 
9
 *    are met:
 
10
 *
 
11
 *        1. Redistributions of source code must retain the above copyright
 
12
 *           notice, this list of conditions and the following disclaimer.
 
13
 *        2. Redistributions in binary form must reproduce the above
 
14
 *           copyright notice, this list of conditions and the following
 
15
 *           disclaimer in the documentation and/or other materials provided
 
16
 *           with the distribution.
 
17
 *        3. Neither the name of the Smart Link Ltd. nor the names of its
 
18
 *           contributors may be used to endorse or promote products derived
 
19
 *           from this software without specific prior written permission.
 
20
 *
 
21
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
22
 *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
23
 *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
24
 *    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
25
 *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
26
 *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
27
 *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
28
 *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
29
 *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
30
 *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
31
 *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
32
 *
 
33
 */
 
34
 
 
35
/*
 
36
 *
 
37
 *    modem_main.c  --  modem main func.
 
38
 *
 
39
 *    Author: Sasha K (sashak@smlink.com)
 
40
 *
 
41
 *
 
42
 */
 
43
 
 
44
#define _GNU_SOURCE
 
45
#include <unistd.h>
 
46
#include <stdlib.h>
 
47
#include <stdio.h>
 
48
#include <string.h>
 
49
#include <errno.h>
 
50
#include <termios.h>
 
51
#include <fcntl.h>
 
52
#include <sys/types.h>
 
53
#include <sys/stat.h>
 
54
#include <sys/ioctl.h>
 
55
#include <sys/mman.h>
 
56
#include <sched.h>
 
57
#include <signal.h>
 
58
#include <limits.h>
 
59
#include <grp.h>
 
60
 
 
61
#ifdef SUPPORT_ALSA
 
62
#define ALSA_PCM_NEW_HW_PARAMS_API 1
 
63
#define ALSA_PCM_NEW_SW_PARAMS_API 1
 
64
#include <alsa/asoundlib.h>
 
65
#endif
 
66
 
 
67
#include <modem.h>
 
68
#include <modem_debug.h>
 
69
 
 
70
#define INFO(fmt,args...) fprintf(stderr, fmt , ##args );
 
71
#define ERR(fmt,args...) fprintf(stderr, "error: " fmt , ##args );
 
72
 
 
73
#define DBG(fmt,args...) dprintf("main: " fmt, ##args)
 
74
 
 
75
 
 
76
#define CLOSE_COUNT_MAX 100
 
77
 
 
78
 
 
79
/* modem init externals : FIXME remove it */
 
80
extern int  dp_dummy_init(void);
 
81
extern void dp_dummy_exit(void);
 
82
extern int  dp_sinus_init(void);
 
83
extern void dp_sinus_exit(void);
 
84
extern int  prop_dp_init(void);
 
85
extern void prop_dp_exit(void);
 
86
extern int datafile_load_info(char *name,struct dsp_info *info);
 
87
extern int datafile_save_info(char *name,struct dsp_info *info);
 
88
 
 
89
/* global config data */
 
90
extern const char *modem_dev_name;
 
91
extern unsigned need_realtime;
 
92
extern const char *modem_group;
 
93
extern mode_t modem_perm;
 
94
 
 
95
 
 
96
 
 
97
struct device_struct {
 
98
        int num;
 
99
        int fd;
 
100
#ifdef SUPPORT_ALSA
 
101
        snd_pcm_t *phandle;
 
102
        snd_pcm_t *chandle;
 
103
        unsigned int period;
 
104
        unsigned int started;
 
105
#endif
 
106
        int delay;
 
107
};
 
108
 
 
109
 
 
110
static char  inbuf[4096];
 
111
static char outbuf[4096];
 
112
 
 
113
 
 
114
/*
 
115
 *    ALSA 'driver'
 
116
 *
 
117
 */
 
118
 
 
119
#ifdef SUPPORT_ALSA
 
120
 
 
121
#define INTERNAL_DELAY 40 /* internal device tx/rx delay: should be selfdetectible */
 
122
 
 
123
extern unsigned use_alsa;
 
124
static snd_output_t *dbg_out = NULL;
 
125
 
 
126
static int alsa_device_setup(struct device_struct *dev, const char *dev_name)
 
127
{
 
128
        struct pollfd pfd;
 
129
        int ret;
 
130
        memset(dev,0,sizeof(*dev));
 
131
        ret = snd_pcm_open(&dev->phandle, dev_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
 
132
        if(ret < 0) {
 
133
                ERR("alsa setup: cannot open playback device '%s': %s",
 
134
                    dev_name, snd_strerror(ret));
 
135
                return -1;
 
136
        }
 
137
        ret = snd_pcm_open(&dev->chandle, dev_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
 
138
        if(ret < 0) {
 
139
                ERR("alsa setup: cannot open playback device '%s': %s",
 
140
                    dev_name, snd_strerror(ret));
 
141
                return -1;
 
142
        }
 
143
        ret = snd_pcm_poll_descriptors(dev->chandle, &pfd, 1);
 
144
        if(ret <= 0) {
 
145
                ERR("alsa setup: cannot get poll descriptors of '%s': %s",
 
146
                    dev_name, snd_strerror(ret));
 
147
                return -1;
 
148
        }
 
149
        dev->fd = pfd.fd;
 
150
        dev->num = 0; /* <-- FIXME */
 
151
 
 
152
        if(modem_debug_level > 0)
 
153
                snd_output_stdio_attach(&dbg_out,stderr,0);
 
154
 
 
155
        return 0;
 
156
}
 
157
 
 
158
static int alsa_device_release(struct device_struct *dev)
 
159
{
 
160
        snd_pcm_close (dev->phandle);
 
161
        snd_pcm_close (dev->chandle);
 
162
        return 0;
 
163
}
 
164
 
 
165
 
 
166
static int alsa_xrun_recovery(struct device_struct *dev)
 
167
{
 
168
        int err;
 
169
        int len;
 
170
        DBG("alsa xrun: try to recover...\n");
 
171
        err = snd_pcm_prepare(dev->phandle);
 
172
        if (err < 0) {
 
173
                ERR("xrun recovery: cannot prepare playback: %s\n", snd_strerror(err));
 
174
                return err;
 
175
        }
 
176
        len = dev->delay - INTERNAL_DELAY;
 
177
        snd_pcm_format_set_silence(SND_PCM_FORMAT_S16_LE, outbuf, len);
 
178
        err = snd_pcm_writei(dev->phandle, outbuf, len);
 
179
        if (err < 0) {
 
180
                ERR("xrun recovery: write error: %s\n", snd_strerror(err));
 
181
                return err;
 
182
        }
 
183
        err = snd_pcm_start(dev->chandle);
 
184
        if(err < 0) {
 
185
                ERR("xrun recovcery snd_pcm_start error: %s\n", snd_strerror(err));
 
186
                return err;
 
187
        }
 
188
        DBG("alsa xrun: recovered.\n");
 
189
        return 0;
 
190
}
 
191
 
 
192
 
 
193
static int alsa_device_read(struct device_struct *dev, char *buf, int count)
 
194
{
 
195
        int ret;
 
196
        do {
 
197
                ret = snd_pcm_readi(dev->chandle,buf,count);
 
198
                if (ret == -EPIPE) {
 
199
                        ret = alsa_xrun_recovery(dev);
 
200
                        break;
 
201
                }
 
202
        } while (ret == -EAGAIN);
 
203
#if 1
 
204
        if(ret != dev->period)
 
205
                DBG("alsa_device_read (%d): %d ...\n",count,ret);
 
206
#endif
 
207
        return ret ;
 
208
}
 
209
 
 
210
static int alsa_device_write(struct device_struct *dev, const char *buf, int count)
 
211
{
 
212
        int asked = count;
 
213
        int written = 0;
 
214
        if(!dev->started)
 
215
                return 0;
 
216
        while(count > 0) {
 
217
                int ret = snd_pcm_writei(dev->phandle,buf,count);
 
218
                if(ret < 0) {
 
219
                        if (ret == -EAGAIN)
 
220
                                continue;
 
221
                        if (ret == -EPIPE) {
 
222
                                ret = alsa_xrun_recovery(dev);
 
223
                        }
 
224
                        written = ret;
 
225
                        break;
 
226
                }
 
227
                count -= ret;
 
228
                buf += ret;
 
229
                written += ret;
 
230
        }
 
231
#if 1
 
232
        if(written != dev->period)
 
233
                DBG("alsa_device_write (%d): %d...\n",asked,written);
 
234
#endif
 
235
        return written;
 
236
}
 
237
 
 
238
 
 
239
static snd_pcm_format_t mdm2snd_format(unsigned mdm_format)
 
240
{
 
241
        if(mdm_format == MFMT_S16_LE)
 
242
                return SND_PCM_FORMAT_S16_LE;
 
243
        return SND_PCM_FORMAT_UNKNOWN;
 
244
}
 
245
 
 
246
 
 
247
static int setup_stream(snd_pcm_t *handle, struct modem *m, const char *stream_name)
 
248
{
 
249
        struct device_struct *dev = m->dev_data;
 
250
        snd_pcm_hw_params_t *hw_params;
 
251
        snd_pcm_sw_params_t *sw_params;
 
252
        snd_pcm_format_t format;
 
253
        unsigned int rate, rrate;
 
254
        snd_pcm_uframes_t size, rsize;
 
255
        int err;
 
256
 
 
257
        err = snd_pcm_hw_params_malloc(&hw_params);
 
258
        if (err < 0) {
 
259
                ERR("cannot alloc hw params for %s: %s\n", stream_name, snd_strerror(err));
 
260
                return err;
 
261
        }
 
262
        err = snd_pcm_hw_params_any(handle,hw_params);
 
263
        if (err < 0) {
 
264
                ERR("cannot init hw params for %s: %s\n", stream_name, snd_strerror(err));
 
265
                return err;
 
266
        }
 
267
        err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
 
268
        if (err < 0) {
 
269
                ERR("cannot set access for %s: %s\n", stream_name, snd_strerror(err));
 
270
                return err;
 
271
        }
 
272
        format = mdm2snd_format(m->format);
 
273
        if(format == SND_PCM_FORMAT_UNKNOWN) {
 
274
                ERR("unsupported format for %s\n",stream_name);
 
275
                return -1;
 
276
        }
 
277
        err = snd_pcm_hw_params_set_format(handle, hw_params, format);
 
278
        if (err < 0) {
 
279
                ERR("cannot set format for %s: %s\n", stream_name, snd_strerror(err));
 
280
                return err;
 
281
        }
 
282
        err = snd_pcm_hw_params_set_channels(handle, hw_params, 1);
 
283
        if (err < 0) {
 
284
                ERR("cannot set channels for %s: %s\n", stream_name, snd_strerror(err));
 
285
                return err;
 
286
        }
 
287
        rrate = rate = m->srate;
 
288
        err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0);
 
289
        if (err < 0) {
 
290
                ERR("cannot set rate for %s: %s\n", stream_name, snd_strerror(err));
 
291
                return err;
 
292
        }
 
293
        if ( rrate != rate ) {
 
294
                ERR("rate %d is not supported by %s (%d).\n",
 
295
                    rate, stream_name, rrate);
 
296
                return -1;
 
297
        }
 
298
        rsize = size = dev->period ;
 
299
        err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &rsize, NULL);
 
300
        if (err < 0) {
 
301
                ERR("cannot set periods for %s: %s\n", stream_name, snd_strerror(err));
 
302
                return err;
 
303
        }
 
304
        if ( rsize != size ) {
 
305
                ERR("period size %ld is not supported by %s (%ld).\n",
 
306
                    size, stream_name, rsize);
 
307
                return -1;              
 
308
        }
 
309
        rsize = size = rsize * 32;
 
310
        err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &rsize);
 
311
        if (err < 0) {
 
312
                ERR("cannot set buffer for %s: %s\n", stream_name, snd_strerror(err));
 
313
                return err;
 
314
        }
 
315
        if ( rsize != size ) {
 
316
                DBG("buffer size for %s is changed %ld -> %ld\n",
 
317
                    stream_name, size, rsize);
 
318
        }
 
319
        err = snd_pcm_hw_params(handle, hw_params);
 
320
        if (err < 0) {
 
321
                ERR("cannot setup hw params for %s: %s\n", stream_name, snd_strerror(err));
 
322
                return err;
 
323
        }
 
324
        err = snd_pcm_prepare(handle);
 
325
        if (err < 0) {
 
326
                ERR("cannot prepare %s: %s\n", stream_name, snd_strerror(err));
 
327
                return err;
 
328
        }
 
329
        snd_pcm_hw_params_free(hw_params);
 
330
 
 
331
        err = snd_pcm_sw_params_malloc(&sw_params);
 
332
        if (err < 0) {
 
333
                ERR("cannot alloc sw params for %s: %s\n", stream_name, snd_strerror(err));
 
334
                return err;
 
335
        }
 
336
        err = snd_pcm_sw_params_current(handle,sw_params);
 
337
        if (err < 0) {
 
338
                ERR("cannot get sw params for %s: %s\n", stream_name, snd_strerror(err));
 
339
                return err;
 
340
        }
 
341
        err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, INT_MAX);
 
342
        if (err < 0) {
 
343
                ERR("cannot set start threshold for %s: %s\n", stream_name, snd_strerror(err));
 
344
                return err;
 
345
        }
 
346
        err = snd_pcm_sw_params_set_avail_min(handle, sw_params, 4);
 
347
        if (err < 0) {
 
348
                ERR("cannot set avail min for %s: %s\n", stream_name, snd_strerror(err));
 
349
                return err;
 
350
        }
 
351
        err = snd_pcm_sw_params_set_xfer_align(handle, sw_params, 4);
 
352
        if (err < 0) {
 
353
                ERR("cannot set align for %s: %s\n", stream_name, snd_strerror(err));
 
354
                return err;
 
355
        }
 
356
        err = snd_pcm_sw_params(handle, sw_params);
 
357
        if (err < 0) {
 
358
                ERR("cannot set sw params for %s: %s\n", stream_name, snd_strerror(err));
 
359
                return err;
 
360
        }
 
361
        snd_pcm_sw_params_free(sw_params);
 
362
 
 
363
        if(modem_debug_level > 0)
 
364
                snd_pcm_dump(handle,dbg_out);
 
365
        return 0;
 
366
}
 
367
 
 
368
static int alsa_start (struct modem *m)
 
369
{
 
370
        struct device_struct *dev = m->dev_data;
 
371
        int err, len;
 
372
        DBG("alsa_start...\n");
 
373
        dev->period = m->frag;
 
374
        err = setup_stream(dev->phandle, m, "playback");
 
375
        if(err < 0)
 
376
                return err;
 
377
        err = setup_stream(dev->chandle, m, "capture");
 
378
        if(err < 0)
 
379
                return err;
 
380
        dev->delay = 0;
 
381
        len = 384;           /* <-- FIXME */
 
382
        DBG("startup write: %d...\n",len);
 
383
        err = snd_pcm_format_set_silence(SND_PCM_FORMAT_S16_LE, outbuf, len);
 
384
        if(err < 0) {
 
385
                ERR("silence error\n");
 
386
                return err;
 
387
        }
 
388
        
 
389
        err = snd_pcm_writei(dev->phandle,outbuf,len);
 
390
        if(err < 0) {
 
391
                ERR("startup write error\n");
 
392
                return err;
 
393
        }
 
394
        dev->delay = err;
 
395
        dev->delay += INTERNAL_DELAY; /* <-- fixme: delay detection is needed */
 
396
        err = snd_pcm_link(dev->chandle, dev->phandle);
 
397
        if(err < 0) {
 
398
                ERR("snd_pcm_link error: %s\n", snd_strerror(err));
 
399
                return err;
 
400
        }
 
401
        err = snd_pcm_start(dev->chandle);
 
402
        if(err < 0) {
 
403
                ERR("snd_pcm_start error: %s\n", snd_strerror(err));
 
404
                return err;
 
405
        }
 
406
        dev->started = 1;
 
407
        return 0;
 
408
}
 
409
 
 
410
static int alsa_stop (struct modem *m)
 
411
{
 
412
        struct device_struct *dev = m->dev_data;
 
413
        DBG("alsa_stop...\n");
 
414
        dev->started = 0;
 
415
        snd_pcm_drop(dev->chandle);
 
416
        snd_pcm_nonblock(dev->phandle, 0);
 
417
        snd_pcm_drain(dev->phandle);
 
418
        snd_pcm_nonblock(dev->phandle, 1);
 
419
        snd_pcm_unlink(dev->chandle);
 
420
        snd_pcm_hw_free(dev->phandle);
 
421
        snd_pcm_hw_free(dev->chandle);
 
422
        return 0;
 
423
}
 
424
 
 
425
static int alsa_ioctl(struct modem *m, unsigned int cmd, unsigned long arg)
 
426
{
 
427
        /* TODO */
 
428
        struct device_struct *dev = m->dev_data;
 
429
        DBG("alsa_ioctl: cmd %x, arg %lx...\n",cmd,arg);
 
430
        switch(cmd) {
 
431
        case MDMCTL_CAPABILITIES:
 
432
                return -EINVAL;
 
433
        case MDMCTL_HOOKSTATE:
 
434
                return 0;
 
435
        case MDMCTL_CODECTYPE:
 
436
                return CODEC_SILABS;
 
437
        case MDMCTL_IODELAY:
 
438
                DBG("delay = %d\n", dev->delay);
 
439
                return dev->delay;
 
440
        default:
 
441
                return 0;
 
442
        }
 
443
        return -EINVAL;
 
444
}
 
445
 
 
446
 
 
447
struct modem_driver alsa_modem_driver = {
 
448
        .name = "alsa modem driver",
 
449
        .start = alsa_start,
 
450
        .stop = alsa_stop,
 
451
        .ioctl = alsa_ioctl,
 
452
};
 
453
 
 
454
 
 
455
#endif
 
456
 
 
457
 
 
458
/*
 
459
 *    'driver' stuff
 
460
 *
 
461
 */
 
462
 
 
463
static int modemap_start (struct modem *m)
 
464
{
 
465
        struct device_struct *dev = m->dev_data;
 
466
        int ret;
 
467
        DBG("modemap_start...\n");
 
468
        dev->delay = 0;
 
469
        ret = ioctl(dev->fd,MDMCTL_START,0);
 
470
        if (ret < 0)
 
471
                return ret;
 
472
        ret = 192*2;
 
473
        memset(outbuf, 0 , ret);
 
474
        ret = write(dev->fd, outbuf, ret);
 
475
        if (ret < 0) {
 
476
                ioctl(dev->fd,MDMCTL_STOP,0);
 
477
                return ret;
 
478
        }
 
479
        dev->delay = ret/2;
 
480
        return 0;
 
481
}
 
482
 
 
483
static int modemap_stop (struct modem *m)
 
484
{
 
485
        struct device_struct *dev = m->dev_data;
 
486
        DBG("modemap_stop...\n");
 
487
        return ioctl(dev->fd,MDMCTL_STOP,0);
 
488
}
 
489
 
 
490
static int modemap_ioctl(struct modem *m, unsigned int cmd, unsigned long arg)
 
491
{
 
492
        struct device_struct *dev = m->dev_data;
 
493
        int ret;
 
494
        DBG("modemap_ioctl: cmd %x, arg %lx...\n",cmd,arg);
 
495
        if (cmd == MDMCTL_SETFRAG)
 
496
                arg <<= MFMT_SHIFT(m->format);
 
497
        ret = ioctl(dev->fd,cmd,arg);
 
498
        if (cmd == MDMCTL_IODELAY && ret > 0) {
 
499
                ret >>= MFMT_SHIFT(m->format);
 
500
                ret += dev->delay;
 
501
        }
 
502
        return ret;
 
503
}
 
504
 
 
505
 
 
506
 
 
507
struct modem_driver mdm_modem_driver = {
 
508
        .name = "modemap driver",
 
509
        .start = modemap_start,
 
510
        .stop = modemap_stop,
 
511
        .ioctl = modemap_ioctl,
 
512
};
 
513
 
 
514
static int mdm_device_read(struct device_struct *dev, char *buf, int size)
 
515
{
 
516
        int ret = read(dev->fd, buf, size*2);
 
517
        if (ret > 0) ret /= 2;
 
518
        return ret;
 
519
}
 
520
 
 
521
static int mdm_device_write(struct device_struct *dev, const char *buf, int size)
 
522
{
 
523
        int ret = write(dev->fd, buf, size*2);
 
524
        if (ret > 0) ret /= 2;
 
525
        return ret;
 
526
}
 
527
 
 
528
static int mdm_device_setup(struct device_struct *dev, const char *dev_name)
 
529
{
 
530
        struct stat stbuf;
 
531
        int ret, fd;
 
532
        memset(dev,0,sizeof(*dev));
 
533
        ret = stat(dev_name,&stbuf);
 
534
        if(ret) {
 
535
                ERR("mdm setup: cannot stat `%s': %s\n", dev_name, strerror(errno));
 
536
                return -1;
 
537
        }
 
538
        if(!S_ISCHR(stbuf.st_mode)) {
 
539
                ERR("mdm setup: not char device `%s'\n", dev_name);
 
540
                return -1;
 
541
        }
 
542
        /* device stuff */
 
543
        fd = open(dev_name,O_RDWR);
 
544
        if(fd < 0) {
 
545
                ERR("mdm setup: cannot open dev `%s': %s\n",dev_name,strerror(errno));
 
546
                return -1;
 
547
        }
 
548
        dev->fd = fd;
 
549
        dev->num = minor(stbuf.st_rdev);
 
550
        return 0;
 
551
}
 
552
 
 
553
static int mdm_device_release(struct device_struct *dev)
 
554
{
 
555
        close(dev->fd);
 
556
        return 0;
 
557
}
 
558
 
 
559
 
 
560
/*
 
561
 *    PTY creation (or re-creation)
 
562
 *
 
563
 */
 
564
 
 
565
static char link_name[PATH_MAX];
 
566
 
 
567
int create_pty(struct modem *m)
 
568
{
 
569
        struct termios termios;
 
570
        const char *pty_name;
 
571
        int pty, ret;
 
572
 
 
573
        if(m->pty)
 
574
                close(m->pty);
 
575
 
 
576
        pty  = getpt();
 
577
        if (pty < 0 || grantpt(pty) < 0 || unlockpt(pty) < 0) {
 
578
                ERR("getpt: %s\n", strerror(errno));
 
579
                return -1;
 
580
        }
 
581
 
 
582
        if(m->pty) {
 
583
                termios = m->termios;
 
584
        }
 
585
        else {
 
586
                ret = tcgetattr(pty, &termios);
 
587
                /* non canonical raw tty */
 
588
                cfmakeraw(&termios);
 
589
                cfsetispeed(&termios, B115200);
 
590
                cfsetospeed(&termios, B115200);
 
591
        }
 
592
 
 
593
        ret = tcsetattr(pty, TCSANOW, &termios);
 
594
        if (ret) {
 
595
                ERR("tcsetattr: %s\n",strerror(errno));
 
596
                return -1;
 
597
        }
 
598
 
 
599
        fcntl(pty,F_SETFL,O_NONBLOCK);
 
600
 
 
601
        pty_name = ptsname(pty);
 
602
 
 
603
        m->pty = pty;
 
604
        m->pty_name = pty_name;
 
605
 
 
606
        modem_update_termios(m,&termios);
 
607
 
 
608
        if(modem_group && *modem_group) {
 
609
                struct group *grp = getgrnam(modem_group);
 
610
                if(!grp) {
 
611
                        ERR("cannot find group '%s': %s\n", modem_group,
 
612
                            strerror(errno));
 
613
                }
 
614
                else {
 
615
                        ret = chown(pty_name, -1, grp->gr_gid);
 
616
                        if(ret < 0) {
 
617
                                ERR("cannot chown '%s' to ':%s': %s\n",
 
618
                                    pty_name, modem_group, strerror(errno));
 
619
                        }
 
620
                }
 
621
        }
 
622
 
 
623
        ret = chmod(pty_name, modem_perm);
 
624
        if (ret < 0) {
 
625
                ERR("cannot chmod '%s' to %o: %s\n",
 
626
                    pty_name, modem_perm, strerror(errno));
 
627
        }
 
628
 
 
629
        if(*link_name) {
 
630
                unlink(link_name);
 
631
                if(symlink(pty_name,link_name)) {
 
632
                        ERR("cannot create symbolink link `%s' -> `%s': %s\n",
 
633
                            link_name,pty_name,strerror(errno));
 
634
                        *link_name = '\0';
 
635
                }
 
636
                else {
 
637
                        INFO("symbolic link `%s' -> `%s' created.\n",
 
638
                             link_name, pty_name);
 
639
                }
 
640
        }
 
641
 
 
642
        return 0;
 
643
}
 
644
 
 
645
 
 
646
/*
 
647
 *    main run cycle
 
648
 *
 
649
 */
 
650
 
 
651
static int (*device_setup)(struct device_struct *dev, const char *dev_name);
 
652
static int (*device_release)(struct device_struct *dev);
 
653
static int (*device_read)(struct device_struct *dev, char *buf, int size);
 
654
static int (*device_write)(struct device_struct *dev, const char *buf, int size);
 
655
static struct modem_driver *modem_driver;
 
656
 
 
657
static volatile sig_atomic_t keep_running = 1;
 
658
 
 
659
void mark_termination(int signum)
 
660
{
 
661
        DBG("signal %d: mark termination.\n",signum);
 
662
        keep_running = 0;
 
663
}
 
664
 
 
665
 
 
666
static int modem_run(struct modem *m, struct device_struct *dev)
 
667
{
 
668
        struct timeval tmo;
 
669
        fd_set rset,eset;
 
670
        struct termios termios;
 
671
        unsigned pty_closed = 0, close_count = 0;
 
672
        int max_fd;
 
673
        int ret, count;
 
674
        void *in;
 
675
 
 
676
        while(keep_running) {
 
677
 
 
678
                if(m->event)
 
679
                        modem_event(m);
 
680
 
 
681
                tmo.tv_sec = 1;
 
682
                tmo.tv_usec= 0;
 
683
                FD_ZERO(&rset);
 
684
                FD_ZERO(&eset);
 
685
                if(m->started)
 
686
                        FD_SET(dev->fd,&rset);
 
687
                FD_SET(dev->fd,&eset);
 
688
                max_fd = dev->fd;
 
689
                
 
690
                if(pty_closed && close_count > 0) {
 
691
                        if(!m->started ||
 
692
                                ++close_count > CLOSE_COUNT_MAX )
 
693
                                close_count = 0;
 
694
                }
 
695
                else if(m->xmit.size - m->xmit.count > 0) {
 
696
                        FD_SET(m->pty,&rset);
 
697
                        if(m->pty > max_fd) max_fd = m->pty;
 
698
                }
 
699
 
 
700
                ret = select(max_fd + 1,&rset,NULL,&eset,&tmo);
 
701
 
 
702
                if (ret < 0) {
 
703
                        if (errno == EINTR)
 
704
                                continue;
 
705
                        ERR("select: %s\n",strerror(errno));
 
706
                        return ret;
 
707
                }
 
708
 
 
709
                if ( ret == 0 )
 
710
                        continue;
 
711
 
 
712
                if(FD_ISSET(dev->fd, &eset)) {
 
713
                        unsigned stat;
 
714
                        //DBG("dev exception...\n");
 
715
#ifdef SUPPORT_ALSA
 
716
                        if(use_alsa) {
 
717
                                DBG("dev exception...\n");
 
718
                                continue;
 
719
                        }
 
720
#endif
 
721
                        ret = ioctl(dev->fd,MDMCTL_GETSTAT,&stat);
 
722
                        if(ret < 0) {
 
723
                                ERR("dev ioctl: %s\n",strerror(errno));
 
724
                                return -1;
 
725
                        }
 
726
                        if(stat&MDMSTAT_ERROR) modem_error(m);
 
727
                        if(stat&MDMSTAT_RING)  modem_ring(m);
 
728
                        continue;
 
729
                }
 
730
                if(FD_ISSET(dev->fd, &rset)) {
 
731
                        count = device_read(dev,inbuf,sizeof(inbuf)/2);
 
732
                        if(count < 0) {
 
733
                                ERR("dev read: %s\n",strerror(errno));
 
734
                                return -1;
 
735
                        }
 
736
                        else if (count == 0) {
 
737
                                DBG("dev read = 0\n");
 
738
                                continue;
 
739
                        }
 
740
                        in = inbuf;
 
741
                        if(m->update_delay < 0) {
 
742
                                if ( -m->update_delay >= count) {
 
743
                                        DBG("change delay -%d...\n", count);
 
744
                                        dev->delay -= count;
 
745
                                        m->update_delay += count;
 
746
                                        continue;
 
747
                                }
 
748
                                DBG("change delay %d...\n", m->update_delay);
 
749
                                in -= m->update_delay;
 
750
                                count += m->update_delay;
 
751
                                dev->delay += m->update_delay;
 
752
                                m->update_delay = 0;
 
753
                        }
 
754
 
 
755
                        modem_process(m,inbuf,outbuf,count);
 
756
                        count = device_write(dev,outbuf,count);
 
757
                        if(count < 0) {
 
758
                                ERR("dev write: %s\n",strerror(errno));
 
759
                                return -1;
 
760
                        }
 
761
                        else if (count == 0) {
 
762
                                DBG("dev write = 0\n");
 
763
                        }
 
764
 
 
765
                        if(m->update_delay > 0) {
 
766
                                DBG("change delay +%d...\n", m->update_delay);
 
767
                                memset(outbuf, 0, m->update_delay*2);
 
768
                                count = device_write(dev,outbuf,m->update_delay);
 
769
                                if(count < 0) {
 
770
                                        ERR("dev write: %s\n",strerror(errno));
 
771
                                        return -1;
 
772
                                }
 
773
                                if(count != m->update_delay) {
 
774
                                        ERR("cannot update delay: %d instead of %d.\n",
 
775
                                            count, m->update_delay);
 
776
                                        return -1;
 
777
                                }
 
778
                                dev->delay += m->update_delay;
 
779
                                m->update_delay = 0;
 
780
                        }
 
781
                }
 
782
                if(FD_ISSET(m->pty,&rset)) {
 
783
                        /* check termios */
 
784
                        tcgetattr(m->pty,&termios);
 
785
                        if(memcmp(&termios,&m->termios,sizeof(termios))) {
 
786
                                DBG("termios changed.\n");
 
787
                                modem_update_termios(m,&termios);
 
788
                        }
 
789
                        /* read data */
 
790
                        count = m->xmit.size - m->xmit.count;
 
791
                        if(count == 0)
 
792
                                continue;
 
793
                        if(count > sizeof(inbuf))
 
794
                                count = sizeof(inbuf);
 
795
                        count = read(m->pty,inbuf,count);
 
796
                        if(count < 0) {
 
797
                                if(errno == EAGAIN) {
 
798
                                        DBG("pty read, errno = EAGAIN\n");
 
799
                                        continue;
 
800
                                }
 
801
                                if(errno == EIO) { /* closed */
 
802
                                        if(!pty_closed) {
 
803
                                                DBG("pty closed.\n");
 
804
                                                if(termios.c_cflag&HUPCL) {
 
805
                                                        modem_hangup(m);
 
806
                                                        /* re-create PTM - simulate hangup */
 
807
                                                        ret = create_pty(m);
 
808
                                                        if (ret < 0) {
 
809
                                                                ERR("cannot re-create PTY.\n");
 
810
                                                                return -1;
 
811
                                                        }
 
812
                                                }
 
813
                                                else
 
814
                                                        pty_closed = 1;
 
815
                                        }
 
816
                                        // DBG("pty read, errno = EIO\n");
 
817
                                        close_count = 1;
 
818
                                        continue;
 
819
                                }
 
820
                                else
 
821
                                        ERR("pty read: %s\n",strerror(errno));
 
822
                                return -1;
 
823
                        }
 
824
                        else if (count == 0) {
 
825
                                DBG("pty read = 0\n");
 
826
                        }
 
827
                        pty_closed = 0;
 
828
                        count = modem_write(m,inbuf,count);
 
829
                        if(count < 0) {
 
830
                                ERR("modem_write failed.\n");
 
831
                                return -1;
 
832
                        }
 
833
                }
 
834
        }
 
835
 
 
836
        return 0;
 
837
}
 
838
 
 
839
 
 
840
int modem_main(const char *dev_name)
 
841
{
 
842
        char path_name[PATH_MAX];
 
843
        struct device_struct device;
 
844
        struct modem *m;
 
845
        int pty;
 
846
        int ret = 0;
 
847
 
 
848
        modem_debug_init(basename(dev_name));
 
849
 
 
850
        ret = device_setup(&device, dev_name);
 
851
        if (ret) {
 
852
                ERR("cannot setup device `%s'\n", dev_name);
 
853
                exit(-1);
 
854
        }
 
855
 
 
856
        dp_dummy_init();
 
857
        dp_sinus_init();
 
858
        prop_dp_init();
 
859
        modem_timer_init();
 
860
 
 
861
        sprintf(link_name,"/dev/ttySL%d", device.num);
 
862
 
 
863
        m = modem_create(modem_driver,basename(dev_name));
 
864
        m->name = basename(dev_name);
 
865
        m->dev_data = &device;
 
866
        m->dev_name = dev_name;
 
867
        
 
868
        ret = create_pty(m);
 
869
        if(ret < 0) {
 
870
                ERR("cannot create PTY.\n");
 
871
                exit(-1);
 
872
        }
 
873
 
 
874
        INFO("modem `%s' created. TTY is `%s'\n",
 
875
             m->name, m->pty_name);
 
876
 
 
877
        sprintf(path_name,"/var/lib/slmodem/data.%s",basename(dev_name));
 
878
        datafile_load_info(path_name,&m->dsp_info);
 
879
 
 
880
        if (need_realtime) {
 
881
                struct sched_param prm;
 
882
                if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
 
883
                        ERR("mlockall: %s\n",strerror(errno));
 
884
                }
 
885
                prm.sched_priority = sched_get_priority_max(SCHED_FIFO);
 
886
                if(sched_setscheduler(0,SCHED_FIFO,&prm)) {
 
887
                        ERR("sched_setscheduler: %s\n",strerror(errno));
 
888
                }
 
889
                DBG("rt applyed: SCHED_FIFO, pri %d\n",prm.sched_priority);
 
890
        }
 
891
 
 
892
        signal(SIGINT, mark_termination);
 
893
        signal(SIGTERM, mark_termination);
 
894
 
 
895
        INFO("Use `%s' as modem device, Ctrl+C for termination.\n",
 
896
             *link_name ? link_name : m->pty_name);
 
897
 
 
898
        /* main loop here */
 
899
        ret = modem_run(m,&device);
 
900
 
 
901
        datafile_save_info(path_name,&m->dsp_info);
 
902
 
 
903
        pty = m->pty;
 
904
        modem_delete(m);
 
905
 
 
906
        usleep(100000);
 
907
        close(pty);
 
908
        if(*link_name)
 
909
                unlink(link_name);
 
910
        
 
911
        dp_dummy_exit();
 
912
        dp_sinus_exit();
 
913
        prop_dp_exit();
 
914
 
 
915
        device_release(&device);
 
916
 
 
917
        modem_debug_exit();
 
918
 
 
919
        exit(ret);
 
920
        return 0;
 
921
}
 
922
 
 
923
 
 
924
 
 
925
 
 
926
int main(int argc, char *argv[])
 
927
{
 
928
        extern void modem_cmdline(int argc, char *argv[]);
 
929
        int ret;
 
930
        modem_cmdline(argc,argv);
 
931
        if(!modem_dev_name) modem_dev_name = "/dev/slamr0";
 
932
 
 
933
        device_setup = mdm_device_setup;
 
934
        device_release = mdm_device_release;
 
935
        device_read = mdm_device_read;
 
936
        device_write = mdm_device_write;
 
937
        modem_driver = &mdm_modem_driver;
 
938
 
 
939
#ifdef SUPPORT_ALSA
 
940
        if(use_alsa) {
 
941
                device_setup = alsa_device_setup;
 
942
                device_release = alsa_device_release;
 
943
                device_read = alsa_device_read;
 
944
                device_write = alsa_device_write;
 
945
                modem_driver = &alsa_modem_driver;
 
946
        }
 
947
#endif
 
948
 
 
949
        ret = modem_main(modem_dev_name);
 
950
        return ret;
 
951
}