// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Stuff used by all variants of the driver
*
* Copyright (c) 2001 by Stefan Eilers,
* Hansjoerg Lipp <hjlipp@web.de>,
* Tilman Schmidt <tilman@imap.cc>.
*
* =====================================================================
* =====================================================================
*/
#include "gigaset.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
/* Version Information */
#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
#define DRIVER_DESC "Driver for Gigaset 307x"
#ifdef CONFIG_GIGASET_DEBUG
#define DRIVER_DESC_DEBUG " (debug build)"
#else
#define DRIVER_DESC_DEBUG ""
#endif
/* Module parameters */
int gigaset_debuglevel;
EXPORT_SYMBOL_GPL(gigaset_debuglevel);
module_param_named(debug, gigaset_debuglevel, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug level");
/* driver state flags */
#define VALID_MINOR 0x01
#define VALID_ID 0x02
/**
* gigaset_dbg_buffer() - dump data in ASCII and hex for debugging
* @level: debugging level.
* @msg: message prefix.
* @len: number of bytes to dump.
* @buf: data to dump.
*
* If the current debugging level includes one of the bits set in @level,
* @len bytes starting at @buf are logged to dmesg at KERN_DEBUG prio,
* prefixed by the text @msg.
*/
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
{
unsigned char outbuf[80];
unsigned char c;
size_t space = sizeof outbuf - 1;
unsigned char *out = outbuf;
size_t numin = len;
while (numin--) {
c = *buf++;
if (c == '~' || c == '^' || c == '\\') {
if (!space--)
break;
*out++ = '\\';
}
if (c & 0x80) {
if (!space--)
break;
*out++ = '~';
c ^= 0x80;
}
if (c < 0x20 || c == 0x7f) {
if (!space--)
break;
*out++ = '^';
c ^= 0x40;
}
if (!space--)
break;
*out++ = c;
}
*out = 0;
gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf);
}
EXPORT_SYMBOL_GPL(gigaset_dbg_buffer);
static int setflags(struct cardstate *cs, unsigned flags, unsigned delay)
{
int r;
r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags);
cs->control_state = flags;
if (r < 0)
return r;
if (delay) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(delay * HZ / 1000);
}
return 0;
}
int gigaset_enterconfigmode(struct cardstate *cs)
{
int i, r;
cs->control_state = TIOCM_RTS;
r = setflags(cs, TIOCM_DTR, 200);
if (r < 0)
goto error;
r = setflags(cs, 0, 200);
if (r < 0)
goto error;
for (i = 0; i < 5; ++i) {
r = setflags(cs, TIOCM_RTS, 100