4
* Copyright (c) 2002, Smart Link Ltd.
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
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.
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.
37
* modem_main.c -- modem main func.
39
* Author: Sasha K (sashak@smlink.com)
52
#include <sys/types.h>
54
#include <sys/ioctl.h>
62
#define ALSA_PCM_NEW_HW_PARAMS_API 1
63
#define ALSA_PCM_NEW_SW_PARAMS_API 1
64
#include <alsa/asoundlib.h>
68
#include <modem_debug.h>
70
#define INFO(fmt,args...) fprintf(stderr, fmt , ##args );
71
#define ERR(fmt,args...) fprintf(stderr, "error: " fmt , ##args );
73
#define DBG(fmt,args...) dprintf("main: " fmt, ##args)
76
#define CLOSE_COUNT_MAX 100
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);
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;
97
struct device_struct {
104
unsigned int started;
110
static char inbuf[4096];
111
static char outbuf[4096];
121
#define INTERNAL_DELAY 40 /* internal device tx/rx delay: should be selfdetectible */
123
extern unsigned use_alsa;
124
static snd_output_t *dbg_out = NULL;
126
static int alsa_device_setup(struct device_struct *dev, const char *dev_name)
130
memset(dev,0,sizeof(*dev));
131
ret = snd_pcm_open(&dev->phandle, dev_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
133
ERR("alsa setup: cannot open playback device '%s': %s",
134
dev_name, snd_strerror(ret));
137
ret = snd_pcm_open(&dev->chandle, dev_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
139
ERR("alsa setup: cannot open playback device '%s': %s",
140
dev_name, snd_strerror(ret));
143
ret = snd_pcm_poll_descriptors(dev->chandle, &pfd, 1);
145
ERR("alsa setup: cannot get poll descriptors of '%s': %s",
146
dev_name, snd_strerror(ret));
150
dev->num = 0; /* <-- FIXME */
152
if(modem_debug_level > 0)
153
snd_output_stdio_attach(&dbg_out,stderr,0);
158
static int alsa_device_release(struct device_struct *dev)
160
snd_pcm_close (dev->phandle);
161
snd_pcm_close (dev->chandle);
166
static int alsa_xrun_recovery(struct device_struct *dev)
170
DBG("alsa xrun: try to recover...\n");
171
err = snd_pcm_prepare(dev->phandle);
173
ERR("xrun recovery: cannot prepare playback: %s\n", snd_strerror(err));
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);
180
ERR("xrun recovery: write error: %s\n", snd_strerror(err));
183
err = snd_pcm_start(dev->chandle);
185
ERR("xrun recovcery snd_pcm_start error: %s\n", snd_strerror(err));
188
DBG("alsa xrun: recovered.\n");
193
static int alsa_device_read(struct device_struct *dev, char *buf, int count)
197
ret = snd_pcm_readi(dev->chandle,buf,count);
199
ret = alsa_xrun_recovery(dev);
202
} while (ret == -EAGAIN);
204
if(ret != dev->period)
205
DBG("alsa_device_read (%d): %d ...\n",count,ret);
210
static int alsa_device_write(struct device_struct *dev, const char *buf, int count)
217
int ret = snd_pcm_writei(dev->phandle,buf,count);
222
ret = alsa_xrun_recovery(dev);
232
if(written != dev->period)
233
DBG("alsa_device_write (%d): %d...\n",asked,written);
239
static snd_pcm_format_t mdm2snd_format(unsigned mdm_format)
241
if(mdm_format == MFMT_S16_LE)
242
return SND_PCM_FORMAT_S16_LE;
243
return SND_PCM_FORMAT_UNKNOWN;
247
static int setup_stream(snd_pcm_t *handle, struct modem *m, const char *stream_name)
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;
257
err = snd_pcm_hw_params_malloc(&hw_params);
259
ERR("cannot alloc hw params for %s: %s\n", stream_name, snd_strerror(err));
262
err = snd_pcm_hw_params_any(handle,hw_params);
264
ERR("cannot init hw params for %s: %s\n", stream_name, snd_strerror(err));
267
err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
269
ERR("cannot set access for %s: %s\n", stream_name, snd_strerror(err));
272
format = mdm2snd_format(m->format);
273
if(format == SND_PCM_FORMAT_UNKNOWN) {
274
ERR("unsupported format for %s\n",stream_name);
277
err = snd_pcm_hw_params_set_format(handle, hw_params, format);
279
ERR("cannot set format for %s: %s\n", stream_name, snd_strerror(err));
282
err = snd_pcm_hw_params_set_channels(handle, hw_params, 1);
284
ERR("cannot set channels for %s: %s\n", stream_name, snd_strerror(err));
287
rrate = rate = m->srate;
288
err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0);
290
ERR("cannot set rate for %s: %s\n", stream_name, snd_strerror(err));
293
if ( rrate != rate ) {
294
ERR("rate %d is not supported by %s (%d).\n",
295
rate, stream_name, rrate);
298
rsize = size = dev->period ;
299
err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &rsize, NULL);
301
ERR("cannot set periods for %s: %s\n", stream_name, snd_strerror(err));
304
if ( rsize != size ) {
305
ERR("period size %ld is not supported by %s (%ld).\n",
306
size, stream_name, rsize);
309
rsize = size = rsize * 32;
310
err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &rsize);
312
ERR("cannot set buffer for %s: %s\n", stream_name, snd_strerror(err));
315
if ( rsize != size ) {
316
DBG("buffer size for %s is changed %ld -> %ld\n",
317
stream_name, size, rsize);
319
err = snd_pcm_hw_params(handle, hw_params);
321
ERR("cannot setup hw params for %s: %s\n", stream_name, snd_strerror(err));
324
err = snd_pcm_prepare(handle);
326
ERR("cannot prepare %s: %s\n", stream_name, snd_strerror(err));
329
snd_pcm_hw_params_free(hw_params);
331
err = snd_pcm_sw_params_malloc(&sw_params);
333
ERR("cannot alloc sw params for %s: %s\n", stream_name, snd_strerror(err));
336
err = snd_pcm_sw_params_current(handle,sw_params);
338
ERR("cannot get sw params for %s: %s\n", stream_name, snd_strerror(err));
341
err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, INT_MAX);
343
ERR("cannot set start threshold for %s: %s\n", stream_name, snd_strerror(err));
346
err = snd_pcm_sw_params_set_avail_min(handle, sw_params, 4);
348
ERR("cannot set avail min for %s: %s\n", stream_name, snd_strerror(err));
351
err = snd_pcm_sw_params_set_xfer_align(handle, sw_params, 4);
353
ERR("cannot set align for %s: %s\n", stream_name, snd_strerror(err));
356
err = snd_pcm_sw_params(handle, sw_params);
358
ERR("cannot set sw params for %s: %s\n", stream_name, snd_strerror(err));
361
snd_pcm_sw_params_free(sw_params);
363
if(modem_debug_level > 0)
364
snd_pcm_dump(handle,dbg_out);
368
static int alsa_start (struct modem *m)
370
struct device_struct *dev = m->dev_data;
372
DBG("alsa_start...\n");
373
dev->period = m->frag;
374
err = setup_stream(dev->phandle, m, "playback");
377
err = setup_stream(dev->chandle, m, "capture");
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);
385
ERR("silence error\n");
389
err = snd_pcm_writei(dev->phandle,outbuf,len);
391
ERR("startup write error\n");
395
dev->delay += INTERNAL_DELAY; /* <-- fixme: delay detection is needed */
396
err = snd_pcm_link(dev->chandle, dev->phandle);
398
ERR("snd_pcm_link error: %s\n", snd_strerror(err));
401
err = snd_pcm_start(dev->chandle);
403
ERR("snd_pcm_start error: %s\n", snd_strerror(err));
410
static int alsa_stop (struct modem *m)
412
struct device_struct *dev = m->dev_data;
413
DBG("alsa_stop...\n");
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);
425
static int alsa_ioctl(struct modem *m, unsigned int cmd, unsigned long arg)
428
struct device_struct *dev = m->dev_data;
429
DBG("alsa_ioctl: cmd %x, arg %lx...\n",cmd,arg);
431
case MDMCTL_CAPABILITIES:
433
case MDMCTL_HOOKSTATE:
435
case MDMCTL_CODECTYPE:
438
DBG("delay = %d\n", dev->delay);
447
struct modem_driver alsa_modem_driver = {
448
.name = "alsa modem driver",
463
static int modemap_start (struct modem *m)
465
struct device_struct *dev = m->dev_data;
467
DBG("modemap_start...\n");
469
ret = ioctl(dev->fd,MDMCTL_START,0);
473
memset(outbuf, 0 , ret);
474
ret = write(dev->fd, outbuf, ret);
476
ioctl(dev->fd,MDMCTL_STOP,0);
483
static int modemap_stop (struct modem *m)
485
struct device_struct *dev = m->dev_data;
486
DBG("modemap_stop...\n");
487
return ioctl(dev->fd,MDMCTL_STOP,0);
490
static int modemap_ioctl(struct modem *m, unsigned int cmd, unsigned long arg)
492
struct device_struct *dev = m->dev_data;
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);
507
struct modem_driver mdm_modem_driver = {
508
.name = "modemap driver",
509
.start = modemap_start,
510
.stop = modemap_stop,
511
.ioctl = modemap_ioctl,
514
static int mdm_device_read(struct device_struct *dev, char *buf, int size)
516
int ret = read(dev->fd, buf, size*2);
517
if (ret > 0) ret /= 2;
521
static int mdm_device_write(struct device_struct *dev, const char *buf, int size)
523
int ret = write(dev->fd, buf, size*2);
524
if (ret > 0) ret /= 2;
528
static int mdm_device_setup(struct device_struct *dev, const char *dev_name)
532
memset(dev,0,sizeof(*dev));
533
ret = stat(dev_name,&stbuf);
535
ERR("mdm setup: cannot stat `%s': %s\n", dev_name, strerror(errno));
538
if(!S_ISCHR(stbuf.st_mode)) {
539
ERR("mdm setup: not char device `%s'\n", dev_name);
543
fd = open(dev_name,O_RDWR);
545
ERR("mdm setup: cannot open dev `%s': %s\n",dev_name,strerror(errno));
549
dev->num = minor(stbuf.st_rdev);
553
static int mdm_device_release(struct device_struct *dev)
561
* PTY creation (or re-creation)
565
static char link_name[PATH_MAX];
567
int create_pty(struct modem *m)
569
struct termios termios;
570
const char *pty_name;
577
if (pty < 0 || grantpt(pty) < 0 || unlockpt(pty) < 0) {
578
ERR("getpt: %s\n", strerror(errno));
583
termios = m->termios;
586
ret = tcgetattr(pty, &termios);
587
/* non canonical raw tty */
589
cfsetispeed(&termios, B115200);
590
cfsetospeed(&termios, B115200);
593
ret = tcsetattr(pty, TCSANOW, &termios);
595
ERR("tcsetattr: %s\n",strerror(errno));
599
fcntl(pty,F_SETFL,O_NONBLOCK);
601
pty_name = ptsname(pty);
604
m->pty_name = pty_name;
606
modem_update_termios(m,&termios);
608
if(modem_group && *modem_group) {
609
struct group *grp = getgrnam(modem_group);
611
ERR("cannot find group '%s': %s\n", modem_group,
615
ret = chown(pty_name, -1, grp->gr_gid);
617
ERR("cannot chown '%s' to ':%s': %s\n",
618
pty_name, modem_group, strerror(errno));
623
ret = chmod(pty_name, modem_perm);
625
ERR("cannot chmod '%s' to %o: %s\n",
626
pty_name, modem_perm, strerror(errno));
631
if(symlink(pty_name,link_name)) {
632
ERR("cannot create symbolink link `%s' -> `%s': %s\n",
633
link_name,pty_name,strerror(errno));
637
INFO("symbolic link `%s' -> `%s' created.\n",
638
link_name, pty_name);
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;
657
static volatile sig_atomic_t keep_running = 1;
659
void mark_termination(int signum)
661
DBG("signal %d: mark termination.\n",signum);
666
static int modem_run(struct modem *m, struct device_struct *dev)
670
struct termios termios;
671
unsigned pty_closed = 0, close_count = 0;
676
while(keep_running) {
686
FD_SET(dev->fd,&rset);
687
FD_SET(dev->fd,&eset);
690
if(pty_closed && close_count > 0) {
692
++close_count > CLOSE_COUNT_MAX )
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;
700
ret = select(max_fd + 1,&rset,NULL,&eset,&tmo);
705
ERR("select: %s\n",strerror(errno));
712
if(FD_ISSET(dev->fd, &eset)) {
714
//DBG("dev exception...\n");
717
DBG("dev exception...\n");
721
ret = ioctl(dev->fd,MDMCTL_GETSTAT,&stat);
723
ERR("dev ioctl: %s\n",strerror(errno));
726
if(stat&MDMSTAT_ERROR) modem_error(m);
727
if(stat&MDMSTAT_RING) modem_ring(m);
730
if(FD_ISSET(dev->fd, &rset)) {
731
count = device_read(dev,inbuf,sizeof(inbuf)/2);
733
ERR("dev read: %s\n",strerror(errno));
736
else if (count == 0) {
737
DBG("dev read = 0\n");
741
if(m->update_delay < 0) {
742
if ( -m->update_delay >= count) {
743
DBG("change delay -%d...\n", count);
745
m->update_delay += count;
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;
755
modem_process(m,inbuf,outbuf,count);
756
count = device_write(dev,outbuf,count);
758
ERR("dev write: %s\n",strerror(errno));
761
else if (count == 0) {
762
DBG("dev write = 0\n");
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);
770
ERR("dev write: %s\n",strerror(errno));
773
if(count != m->update_delay) {
774
ERR("cannot update delay: %d instead of %d.\n",
775
count, m->update_delay);
778
dev->delay += m->update_delay;
782
if(FD_ISSET(m->pty,&rset)) {
784
tcgetattr(m->pty,&termios);
785
if(memcmp(&termios,&m->termios,sizeof(termios))) {
786
DBG("termios changed.\n");
787
modem_update_termios(m,&termios);
790
count = m->xmit.size - m->xmit.count;
793
if(count > sizeof(inbuf))
794
count = sizeof(inbuf);
795
count = read(m->pty,inbuf,count);
797
if(errno == EAGAIN) {
798
DBG("pty read, errno = EAGAIN\n");
801
if(errno == EIO) { /* closed */
803
DBG("pty closed.\n");
804
if(termios.c_cflag&HUPCL) {
806
/* re-create PTM - simulate hangup */
809
ERR("cannot re-create PTY.\n");
816
// DBG("pty read, errno = EIO\n");
821
ERR("pty read: %s\n",strerror(errno));
824
else if (count == 0) {
825
DBG("pty read = 0\n");
828
count = modem_write(m,inbuf,count);
830
ERR("modem_write failed.\n");
840
int modem_main(const char *dev_name)
842
char path_name[PATH_MAX];
843
struct device_struct device;
848
modem_debug_init(basename(dev_name));
850
ret = device_setup(&device, dev_name);
852
ERR("cannot setup device `%s'\n", dev_name);
861
sprintf(link_name,"/dev/ttySL%d", device.num);
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;
870
ERR("cannot create PTY.\n");
874
INFO("modem `%s' created. TTY is `%s'\n",
875
m->name, m->pty_name);
877
sprintf(path_name,"/var/lib/slmodem/data.%s",basename(dev_name));
878
datafile_load_info(path_name,&m->dsp_info);
881
struct sched_param prm;
882
if(mlockall(MCL_CURRENT|MCL_FUTURE)) {
883
ERR("mlockall: %s\n",strerror(errno));
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));
889
DBG("rt applyed: SCHED_FIFO, pri %d\n",prm.sched_priority);
892
signal(SIGINT, mark_termination);
893
signal(SIGTERM, mark_termination);
895
INFO("Use `%s' as modem device, Ctrl+C for termination.\n",
896
*link_name ? link_name : m->pty_name);
899
ret = modem_run(m,&device);
901
datafile_save_info(path_name,&m->dsp_info);
915
device_release(&device);
926
int main(int argc, char *argv[])
928
extern void modem_cmdline(int argc, char *argv[]);
930
modem_cmdline(argc,argv);
931
if(!modem_dev_name) modem_dev_name = "/dev/slamr0";
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;
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;
949
ret = modem_main(modem_dev_name);