Overhaul ucom serial driver by using generic stuff instead of homerolled
all over the place.
This commit is contained in:
parent
e8d3e08098
commit
d75207f145
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=135379
@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/clist.h>
|
||||
#include <sys/file.h>
|
||||
@ -116,41 +117,34 @@ SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW,
|
||||
#define DPRINTFN(n, x)
|
||||
#endif
|
||||
|
||||
Static d_open_t ucomopen;
|
||||
Static d_close_t ucomclose;
|
||||
Static d_read_t ucomread;
|
||||
Static d_write_t ucomwrite;
|
||||
Static d_ioctl_t ucomioctl;
|
||||
|
||||
|
||||
static struct cdevsw ucom_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_open = ucomopen,
|
||||
.d_close = ucomclose,
|
||||
.d_read = ucomread,
|
||||
.d_write = ucomwrite,
|
||||
.d_ioctl = ucomioctl,
|
||||
.d_open = ttyopen,
|
||||
.d_close = ttyclose,
|
||||
.d_name = "ucom",
|
||||
.d_flags = D_TTY | D_NEEDGIANT,
|
||||
#if __FreeBSD_version < 500014
|
||||
.d_bmaj = -1,
|
||||
#endif
|
||||
};
|
||||
|
||||
Static void ucom_cleanup(struct ucom_softc *);
|
||||
Static int ucomctl(struct ucom_softc *, int, int);
|
||||
Static int ucomparam(struct tty *, struct termios *);
|
||||
Static void ucomstart(struct tty *);
|
||||
Static void ucomstop(struct tty *, int);
|
||||
Static void ucom_shutdown(struct ucom_softc *);
|
||||
Static void ucom_dtr(struct ucom_softc *, int);
|
||||
Static void ucom_rts(struct ucom_softc *, int);
|
||||
Static void ucom_break(struct ucom_softc *, int);
|
||||
Static void ucombreak(struct tty *, int);
|
||||
Static usbd_status ucomstartread(struct ucom_softc *);
|
||||
Static void ucomreadcb(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
||||
Static void ucomwritecb(usbd_xfer_handle, usbd_private_handle, usbd_status);
|
||||
Static void ucomstopread(struct ucom_softc *);
|
||||
|
||||
Static t_open_t ucomopen;
|
||||
Static t_close_t ucomclose;
|
||||
Static t_modem_t ucommodem;
|
||||
Static t_ioctl_t ucomioctl;
|
||||
|
||||
devclass_t ucom_devclass;
|
||||
|
||||
static moduledata_t ucom_mod = {
|
||||
@ -171,19 +165,25 @@ ucom_attach(struct ucom_softc *sc)
|
||||
|
||||
unit = device_get_unit(sc->sc_dev);
|
||||
|
||||
sc->sc_tty = tp = ttymalloc(sc->sc_tty);
|
||||
tp->t_oproc = ucomstart;
|
||||
tp->t_param = ucomparam;
|
||||
tp->t_stop = ucomstop;
|
||||
|
||||
DPRINTF(("ucom_attach: tty_attach tp = %p\n", tp));
|
||||
|
||||
DPRINTF(("ucom_attach: make_dev: ucom%d\n", unit));
|
||||
|
||||
sc->sc_tty = tp = ttyalloc();
|
||||
sc->dev = make_dev(&ucom_cdevsw, unit | UCOM_CALLOUT_MASK,
|
||||
UID_UUCP, GID_DIALER, 0660,
|
||||
"ucom%d", unit);
|
||||
sc->dev->si_tty = tp;
|
||||
tp->t_dev = sc->dev;
|
||||
tp->t_sc = sc;
|
||||
tp->t_oproc = ucomstart;
|
||||
tp->t_param = ucomparam;
|
||||
tp->t_stop = ucomstop;
|
||||
tp->t_break = ucombreak;
|
||||
tp->t_open = ucomopen;
|
||||
tp->t_close = ucomclose;
|
||||
tp->t_modem = ucommodem;
|
||||
tp->t_ioctl = ucomioctl;
|
||||
|
||||
DPRINTF(("ucom_attach: tty_attach tp = %p\n", tp));
|
||||
|
||||
DPRINTF(("ucom_attach: make_dev: ucom%d\n", unit));
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -197,6 +197,7 @@ ucom_detach(struct ucom_softc *sc)
|
||||
DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty));
|
||||
|
||||
sc->sc_dying = 1;
|
||||
ttygone(sc->sc_tty);
|
||||
|
||||
if (sc->sc_bulkin_pipe != NULL)
|
||||
usbd_abort_pipe(sc->sc_bulkin_pipe);
|
||||
@ -238,475 +239,201 @@ ucom_shutdown(struct ucom_softc *sc)
|
||||
* notice even if we immediately open the port again.
|
||||
*/
|
||||
if (ISSET(tp->t_cflag, HUPCL)) {
|
||||
(void)ucomctl(sc, TIOCM_DTR, DMBIC);
|
||||
(void)ucommodem(tp, 0, SER_DTR);
|
||||
(void)tsleep(sc, TTIPRI, "ucomsd", hz);
|
||||
}
|
||||
}
|
||||
|
||||
Static int
|
||||
ucomopen(struct cdev *dev, int flag, int mode, usb_proc_ptr p)
|
||||
ucomopen(struct tty *tp, struct cdev *dev)
|
||||
{
|
||||
int unit = UCOMUNIT(dev);
|
||||
struct ucom_softc *sc;
|
||||
usbd_status err;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
int error;
|
||||
|
||||
USB_GET_SC_OPEN(ucom, unit, sc);
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (ENXIO);
|
||||
|
||||
tp = sc->sc_tty;
|
||||
|
||||
DPRINTF(("%s: ucomopen: tp = %p\n", USBDEVNAME(sc->sc_dev), tp));
|
||||
|
||||
if (ISSET(tp->t_state, TS_ISOPEN) &&
|
||||
ISSET(tp->t_state, TS_XCLUDE) &&
|
||||
suser(p))
|
||||
return (EBUSY);
|
||||
sc->sc_poll = 0;
|
||||
sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
|
||||
|
||||
/*
|
||||
* Do the following iff this is a first open.
|
||||
*/
|
||||
s = spltty();
|
||||
while (sc->sc_opening)
|
||||
tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
|
||||
sc->sc_opening = 1;
|
||||
(void)ucommodem(tp, SER_DTR | SER_RTS, 0);
|
||||
|
||||
if (!ISSET(tp->t_state, TS_ISOPEN)) {
|
||||
struct termios t;
|
||||
|
||||
sc->sc_poll = 0;
|
||||
sc->sc_lsr = sc->sc_msr = sc->sc_mcr = 0;
|
||||
|
||||
tp->t_dev = dev;
|
||||
|
||||
/*
|
||||
* Initialize the termios status to the defaults. Add in the
|
||||
* sticky bits from TIOCSFLAGS.
|
||||
*/
|
||||
t.c_ispeed = 0;
|
||||
t.c_ospeed = TTYDEF_SPEED;
|
||||
t.c_cflag = TTYDEF_CFLAG;
|
||||
/* Make sure ucomparam() will do something. */
|
||||
tp->t_ospeed = 0;
|
||||
(void)ucomparam(tp, &t);
|
||||
tp->t_iflag = TTYDEF_IFLAG;
|
||||
tp->t_oflag = TTYDEF_OFLAG;
|
||||
tp->t_lflag = TTYDEF_LFLAG;
|
||||
ttychars(tp);
|
||||
ttsetwater(tp);
|
||||
|
||||
/*
|
||||
* Turn on DTR. We must always do this, even if carrier is not
|
||||
* present, because otherwise we'd have to use TIOCSDTR
|
||||
* immediately after setting CLOCAL, which applications do not
|
||||
* expect. We always assert DTR while the device is open
|
||||
* unless explicitly requested to deassert it.
|
||||
*/
|
||||
(void)ucomctl(sc, TIOCM_DTR | TIOCM_RTS, DMBIS);
|
||||
|
||||
/* Device specific open */
|
||||
if (sc->sc_callback->ucom_open != NULL) {
|
||||
error = sc->sc_callback->ucom_open(sc->sc_parent,
|
||||
sc->sc_portno);
|
||||
if (error) {
|
||||
ucom_cleanup(sc);
|
||||
sc->sc_opening = 0;
|
||||
wakeup(&sc->sc_opening);
|
||||
splx(s);
|
||||
return (error);
|
||||
}
|
||||
/* Device specific open */
|
||||
if (sc->sc_callback->ucom_open != NULL) {
|
||||
error = sc->sc_callback->ucom_open(sc->sc_parent,
|
||||
sc->sc_portno);
|
||||
if (error) {
|
||||
ucom_cleanup(sc);
|
||||
splx(s);
|
||||
return (error);
|
||||
}
|
||||
|
||||
DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
|
||||
sc->sc_bulkin_no, sc->sc_bulkout_no));
|
||||
|
||||
/* Open the bulk pipes */
|
||||
/* Bulk-in pipe */
|
||||
err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
|
||||
&sc->sc_bulkin_pipe);
|
||||
if (err) {
|
||||
printf("%s: open bulk in error (addr %d): %s\n",
|
||||
USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
|
||||
usbd_errstr(err));
|
||||
error = EIO;
|
||||
goto fail_0;
|
||||
}
|
||||
/* Bulk-out pipe */
|
||||
err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
|
||||
USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
|
||||
if (err) {
|
||||
printf("%s: open bulk out error (addr %d): %s\n",
|
||||
USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
|
||||
usbd_errstr(err));
|
||||
error = EIO;
|
||||
goto fail_1;
|
||||
}
|
||||
|
||||
/* Allocate a request and an input buffer and start reading. */
|
||||
sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
|
||||
if (sc->sc_ixfer == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail_2;
|
||||
}
|
||||
|
||||
sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
|
||||
sc->sc_ibufsizepad);
|
||||
if (sc->sc_ibuf == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail_3;
|
||||
}
|
||||
|
||||
sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
|
||||
if (sc->sc_oxfer == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail_3;
|
||||
}
|
||||
|
||||
sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
|
||||
sc->sc_obufsize +
|
||||
sc->sc_opkthdrlen);
|
||||
if (sc->sc_obuf == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail_4;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle initial DCD.
|
||||
*/
|
||||
if (ISSET(sc->sc_msr, UMSR_DCD) ||
|
||||
(minor(dev) & UCOM_CALLOUT_MASK))
|
||||
ttyld_modem(tp, 1);
|
||||
|
||||
ucomstartread(sc);
|
||||
}
|
||||
|
||||
sc->sc_opening = 0;
|
||||
wakeup(&sc->sc_opening);
|
||||
splx(s);
|
||||
DPRINTF(("ucomopen: open pipes in = %d out = %d\n",
|
||||
sc->sc_bulkin_no, sc->sc_bulkout_no));
|
||||
|
||||
error = tty_open(dev, tp);
|
||||
if (error)
|
||||
goto bad;
|
||||
/* Open the bulk pipes */
|
||||
/* Bulk-in pipe */
|
||||
err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, 0,
|
||||
&sc->sc_bulkin_pipe);
|
||||
if (err) {
|
||||
printf("%s: open bulk in error (addr %d): %s\n",
|
||||
USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no,
|
||||
usbd_errstr(err));
|
||||
error = EIO;
|
||||
goto fail;
|
||||
}
|
||||
/* Bulk-out pipe */
|
||||
err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
|
||||
USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
|
||||
if (err) {
|
||||
printf("%s: open bulk out error (addr %d): %s\n",
|
||||
USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no,
|
||||
usbd_errstr(err));
|
||||
error = EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
error = ttyld_open(tp, dev);
|
||||
if (error)
|
||||
goto bad;
|
||||
/* Allocate a request and an input buffer and start reading. */
|
||||
sc->sc_ixfer = usbd_alloc_xfer(sc->sc_udev);
|
||||
if (sc->sc_ixfer == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ttyldoptim(tp);
|
||||
sc->sc_ibuf = usbd_alloc_buffer(sc->sc_ixfer,
|
||||
sc->sc_ibufsizepad);
|
||||
if (sc->sc_ibuf == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DPRINTF(("%s: ucomopen: success\n", USBDEVNAME(sc->sc_dev)));
|
||||
sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev);
|
||||
if (sc->sc_oxfer == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sc->sc_obuf = usbd_alloc_buffer(sc->sc_oxfer,
|
||||
sc->sc_obufsize +
|
||||
sc->sc_opkthdrlen);
|
||||
if (sc->sc_obuf == NULL) {
|
||||
error = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ucomstartread(sc);
|
||||
|
||||
sc->sc_poll = 1;
|
||||
sc->sc_refcnt++;
|
||||
|
||||
return (0);
|
||||
|
||||
fail_4:
|
||||
usbd_free_xfer(sc->sc_oxfer);
|
||||
sc->sc_oxfer = NULL;
|
||||
fail_3:
|
||||
usbd_free_xfer(sc->sc_ixfer);
|
||||
sc->sc_ixfer = NULL;
|
||||
fail_2:
|
||||
usbd_close_pipe(sc->sc_bulkout_pipe);
|
||||
sc->sc_bulkout_pipe = NULL;
|
||||
fail_1:
|
||||
usbd_close_pipe(sc->sc_bulkin_pipe);
|
||||
sc->sc_bulkin_pipe = NULL;
|
||||
fail_0:
|
||||
sc->sc_opening = 0;
|
||||
wakeup(&sc->sc_opening);
|
||||
fail:
|
||||
splx(s);
|
||||
return (error);
|
||||
|
||||
bad:
|
||||
if (!ISSET(tp->t_state, TS_ISOPEN)) {
|
||||
/*
|
||||
* We failed to open the device, and nobody else had it opened.
|
||||
* Clean up the state as appropriate.
|
||||
*/
|
||||
ucom_cleanup(sc);
|
||||
}
|
||||
|
||||
DPRINTF(("%s: ucomopen: failed\n", USBDEVNAME(sc->sc_dev)));
|
||||
|
||||
ucom_cleanup(sc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ucomclose(struct cdev *dev, int flag, int mode, usb_proc_ptr p)
|
||||
static void
|
||||
ucomclose(struct tty *tp)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct tty *tp;
|
||||
int s;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(dev), sc);
|
||||
sc = tp->t_sc;
|
||||
|
||||
tp = sc->sc_tty;
|
||||
DPRINTF(("%s: ucomclose \n", USBDEVNAME(sc->sc_dev)));
|
||||
|
||||
DPRINTF(("%s: ucomclose: unit = %d\n",
|
||||
USBDEVNAME(sc->sc_dev), UCOMUNIT(dev)));
|
||||
|
||||
if (!ISSET(tp->t_state, TS_ISOPEN))
|
||||
goto quit;
|
||||
|
||||
s = spltty();
|
||||
ttyld_close(tp, flag);
|
||||
ttyldoptim(tp);
|
||||
tty_close(tp);
|
||||
splx(s);
|
||||
|
||||
if (sc->sc_dying)
|
||||
goto quit;
|
||||
|
||||
if (!ISSET(tp->t_state, TS_ISOPEN)) {
|
||||
/*
|
||||
* Although we got a last close, the device may still be in
|
||||
* use; e.g. if this was the dialout node, and there are still
|
||||
* processes waiting for carrier on the non-dialout node.
|
||||
*/
|
||||
ucom_cleanup(sc);
|
||||
}
|
||||
ucom_cleanup(sc);
|
||||
|
||||
if (sc->sc_callback->ucom_close != NULL)
|
||||
sc->sc_callback->ucom_close(sc->sc_parent, sc->sc_portno);
|
||||
|
||||
quit:
|
||||
if (--sc->sc_refcnt < 0)
|
||||
usb_detach_wakeup(USBDEV(sc->sc_dev));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ucomread(struct cdev *dev, struct uio *uio, int flag)
|
||||
ucomioctl(struct tty *tp, u_long cmd, void *data, int flag, usb_proc_ptr p)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct tty *tp;
|
||||
int error;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(dev), sc);
|
||||
tp = sc->sc_tty;
|
||||
|
||||
DPRINTF(("ucomread: tp = %p, flag = 0x%x\n", tp, flag));
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
|
||||
error = ttyld_read(tp, uio, flag);
|
||||
|
||||
DPRINTF(("ucomread: error = %d\n", error));
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ucomwrite(struct cdev *dev, struct uio *uio, int flag)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct tty *tp;
|
||||
int error;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(dev), sc);
|
||||
tp = sc->sc_tty;
|
||||
|
||||
DPRINTF(("ucomwrite: tp = %p, flag = 0x%x\n", tp, flag));
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
|
||||
error = ttyld_write(tp, uio, flag);
|
||||
|
||||
DPRINTF(("ucomwrite: error = %d\n", error));
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ucomioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, usb_proc_ptr p)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
struct tty *tp;
|
||||
int error;
|
||||
int s;
|
||||
int d;
|
||||
#if defined(COMPAT_43)
|
||||
u_long oldcmd;
|
||||
struct termios term;
|
||||
#endif
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(dev), sc);
|
||||
tp = sc->sc_tty;
|
||||
|
||||
sc = tp->t_sc;;
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
|
||||
DPRINTF(("ucomioctl: cmd = 0x%08lx\n", cmd));
|
||||
|
||||
#if defined(COMPAT_43)
|
||||
term = tp->t_termios;
|
||||
oldcmd = cmd;
|
||||
error = ttsetcompat(tp, &cmd, data, &term);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (cmd != oldcmd)
|
||||
data = (caddr_t)&term;
|
||||
#endif
|
||||
|
||||
error = ttyioctl(dev, cmd, data, flag, p);
|
||||
ttyldoptim(tp);
|
||||
if (error != ENOTTY) {
|
||||
DPRINTF(("ucomioctl: l_ioctl: error = %d\n", error));
|
||||
return (error);
|
||||
}
|
||||
|
||||
s = spltty();
|
||||
|
||||
if (sc->sc_callback->ucom_ioctl != NULL) {
|
||||
error = ENOTTY;
|
||||
if (sc->sc_callback->ucom_ioctl != NULL)
|
||||
error = sc->sc_callback->ucom_ioctl(sc->sc_parent,
|
||||
sc->sc_portno,
|
||||
cmd, data, flag, p);
|
||||
if (error >= 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
DPRINTF(("ucomioctl: our cmd = 0x%08lx\n", cmd));
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCSBRK:
|
||||
DPRINTF(("ucomioctl: TIOCSBRK\n"));
|
||||
ucom_break(sc, 1);
|
||||
break;
|
||||
case TIOCCBRK:
|
||||
DPRINTF(("ucomioctl: TIOCCBRK\n"));
|
||||
ucom_break(sc, 0);
|
||||
break;
|
||||
|
||||
case TIOCSDTR:
|
||||
DPRINTF(("ucomioctl: TIOCSDTR\n"));
|
||||
(void)ucomctl(sc, TIOCM_DTR, DMBIS);
|
||||
break;
|
||||
case TIOCCDTR:
|
||||
DPRINTF(("ucomioctl: TIOCCDTR\n"));
|
||||
(void)ucomctl(sc, TIOCM_DTR, DMBIC);
|
||||
break;
|
||||
|
||||
case TIOCMSET:
|
||||
d = *(int *)data;
|
||||
DPRINTF(("ucomioctl: TIOCMSET, 0x%x\n", d));
|
||||
(void)ucomctl(sc, d, DMSET);
|
||||
break;
|
||||
case TIOCMBIS:
|
||||
d = *(int *)data;
|
||||
DPRINTF(("ucomioctl: TIOCMBIS, 0x%x\n", d));
|
||||
(void)ucomctl(sc, d, DMBIS);
|
||||
break;
|
||||
case TIOCMBIC:
|
||||
d = *(int *)data;
|
||||
DPRINTF(("ucomioctl: TIOCMBIC, 0x%x\n", d));
|
||||
(void)ucomctl(sc, d, DMBIC);
|
||||
break;
|
||||
case TIOCMGET:
|
||||
d = ucomctl(sc, 0, DMGET);
|
||||
DPRINTF(("ucomioctl: TIOCMGET, 0x%x\n", d));
|
||||
*(int *)data = d;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF(("ucomioctl: error: our cmd = 0x%08lx\n", cmd));
|
||||
error = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
splx(s);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
Static int
|
||||
ucomctl(struct ucom_softc *sc, int bits, int how)
|
||||
ucommodem(struct tty *tp, int sigon, int sigoff)
|
||||
{
|
||||
struct ucom_softc *sc;
|
||||
int mcr;
|
||||
int msr;
|
||||
int onoff;
|
||||
|
||||
DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits, how));
|
||||
|
||||
if (how == DMGET) {
|
||||
SET(bits, TIOCM_LE); /* always set TIOCM_LE bit */
|
||||
DPRINTF(("ucomctl: DMGET: LE"));
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sigon == 0 && sigoff == 0) {
|
||||
mcr = sc->sc_mcr;
|
||||
if (ISSET(mcr, UMCR_DTR)) {
|
||||
SET(bits, TIOCM_DTR);
|
||||
DPRINTF((" DTR"));
|
||||
}
|
||||
if (ISSET(mcr, UMCR_RTS)) {
|
||||
SET(bits, TIOCM_RTS);
|
||||
DPRINTF((" RTS"));
|
||||
}
|
||||
if (ISSET(mcr, SER_DTR))
|
||||
sigon |= SER_DTR;
|
||||
if (ISSET(mcr, SER_RTS))
|
||||
sigon |= SER_RTS;
|
||||
|
||||
msr = sc->sc_msr;
|
||||
if (ISSET(msr, UMSR_CTS)) {
|
||||
SET(bits, TIOCM_CTS);
|
||||
DPRINTF((" CTS"));
|
||||
}
|
||||
if (ISSET(msr, UMSR_DCD)) {
|
||||
SET(bits, TIOCM_CD);
|
||||
DPRINTF((" CD"));
|
||||
}
|
||||
if (ISSET(msr, UMSR_DSR)) {
|
||||
SET(bits, TIOCM_DSR);
|
||||
DPRINTF((" DSR"));
|
||||
}
|
||||
if (ISSET(msr, UMSR_RI)) {
|
||||
SET(bits, TIOCM_RI);
|
||||
DPRINTF((" RI"));
|
||||
}
|
||||
|
||||
DPRINTF(("\n"));
|
||||
|
||||
return (bits);
|
||||
if (ISSET(msr, SER_CTS))
|
||||
sigon |= SER_CTS;
|
||||
if (ISSET(msr, SER_DCD))
|
||||
sigon |= SER_DCD;
|
||||
if (ISSET(msr, SER_DSR))
|
||||
sigon |= SER_DSR;
|
||||
if (ISSET(msr, SER_RI))
|
||||
sigon |= SER_RI;
|
||||
return (sigon);
|
||||
}
|
||||
|
||||
mcr = 0;
|
||||
if (ISSET(bits, TIOCM_DTR))
|
||||
SET(mcr, UMCR_DTR);
|
||||
if (ISSET(bits, TIOCM_RTS))
|
||||
SET(mcr, UMCR_RTS);
|
||||
mcr = sc->sc_mcr;
|
||||
if (ISSET(sigon, SER_DTR))
|
||||
mcr |= SER_DTR;
|
||||
if (ISSET(sigoff, SER_DTR))
|
||||
mcr &= ~SER_DTR;
|
||||
if (ISSET(sigon, SER_RTS))
|
||||
mcr |= SER_RTS;
|
||||
if (ISSET(sigoff, SER_RTS))
|
||||
mcr &= ~SER_RTS;
|
||||
sc->sc_mcr = mcr;
|
||||
|
||||
switch (how) {
|
||||
case DMSET:
|
||||
sc->sc_mcr = mcr;
|
||||
break;
|
||||
case DMBIS:
|
||||
sc->sc_mcr |= mcr;
|
||||
break;
|
||||
case DMBIC:
|
||||
sc->sc_mcr &= ~mcr;
|
||||
break;
|
||||
}
|
||||
|
||||
onoff = ISSET(sc->sc_mcr, UMCR_DTR) ? 1 : 0;
|
||||
onoff = ISSET(sc->sc_mcr, SER_DTR) ? 1 : 0;
|
||||
ucom_dtr(sc, onoff);
|
||||
|
||||
onoff = ISSET(sc->sc_mcr, UMCR_RTS) ? 1 : 0;
|
||||
onoff = ISSET(sc->sc_mcr, SER_RTS) ? 1 : 0;
|
||||
ucom_rts(sc, onoff);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
Static void
|
||||
ucom_break(struct ucom_softc *sc, int onoff)
|
||||
ucombreak(struct tty *tp, int onoff)
|
||||
{
|
||||
DPRINTF(("ucom_break: onoff = %d\n", onoff));
|
||||
struct ucom_softc *sc;
|
||||
|
||||
sc = tp->t_sc;
|
||||
DPRINTF(("ucombreak: onoff = %d\n", onoff));
|
||||
if (sc->sc_callback->ucom_set == NULL)
|
||||
return;
|
||||
sc->sc_callback->ucom_set(sc->sc_parent, sc->sc_portno,
|
||||
@ -751,10 +478,10 @@ ucom_status_change(struct ucom_softc *sc)
|
||||
old_msr = sc->sc_msr;
|
||||
sc->sc_callback->ucom_get_status(sc->sc_parent, sc->sc_portno,
|
||||
&sc->sc_lsr, &sc->sc_msr);
|
||||
if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
|
||||
if (ISSET((sc->sc_msr ^ old_msr), SER_DCD)) {
|
||||
if (sc->sc_poll == 0)
|
||||
return;
|
||||
onoff = ISSET(sc->sc_msr, UMSR_DCD) ? 1 : 0;
|
||||
onoff = ISSET(sc->sc_msr, SER_DCD) ? 1 : 0;
|
||||
DPRINTF(("ucom_status_change: DCD changed to %d\n", onoff));
|
||||
ttyld_modem(tp, onoff);
|
||||
}
|
||||
@ -767,7 +494,7 @@ ucomparam(struct tty *tp, struct termios *t)
|
||||
int error;
|
||||
usbd_status uerr;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
|
||||
sc = tp->t_sc;
|
||||
|
||||
if (sc->sc_dying)
|
||||
return (EIO);
|
||||
@ -815,7 +542,7 @@ ucomparam(struct tty *tp, struct termios *t)
|
||||
sc->sc_state |= UCS_RTS_IFLOW;
|
||||
} else if (sc->sc_state & UCS_RTS_IFLOW) {
|
||||
sc->sc_state &= ~UCS_RTS_IFLOW;
|
||||
(void)ucomctl(sc, UMCR_RTS, DMBIS);
|
||||
(void)ucommodem(tp, SER_RTS, 0);
|
||||
}
|
||||
|
||||
ttyldoptim(tp);
|
||||
@ -837,7 +564,7 @@ ucomstart(struct tty *tp)
|
||||
u_char *data;
|
||||
int cnt;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
|
||||
sc = tp->t_sc;
|
||||
DPRINTF(("ucomstart: sc = %p\n", sc));
|
||||
|
||||
if (sc->sc_dying)
|
||||
@ -846,17 +573,17 @@ ucomstart(struct tty *tp)
|
||||
s = spltty();
|
||||
|
||||
if (tp->t_state & TS_TBLOCK) {
|
||||
if (ISSET(sc->sc_mcr, UMCR_RTS) &&
|
||||
if (ISSET(sc->sc_mcr, SER_RTS) &&
|
||||
ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
|
||||
DPRINTF(("ucomstart: clear RTS\n"));
|
||||
(void)ucomctl(sc, UMCR_RTS, DMBIC);
|
||||
(void)ucommodem(tp, 0, SER_RTS);
|
||||
}
|
||||
} else {
|
||||
if (!ISSET(sc->sc_mcr, UMCR_RTS) &&
|
||||
if (!ISSET(sc->sc_mcr, SER_RTS) &&
|
||||
tp->t_rawq.c_cc <= tp->t_ilowat &&
|
||||
ISSET(sc->sc_state, UCS_RTS_IFLOW)) {
|
||||
DPRINTF(("ucomstart: set RTS\n"));
|
||||
(void)ucomctl(sc, UMCR_RTS, DMBIS);
|
||||
(void)ucommodem(tp, SER_RTS, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -925,7 +652,7 @@ ucomstop(struct tty *tp, int flag)
|
||||
struct ucom_softc *sc;
|
||||
int s;
|
||||
|
||||
USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc);
|
||||
sc = tp->t_sc;
|
||||
|
||||
DPRINTF(("ucomstop: %d\n", flag));
|
||||
|
||||
@ -1109,9 +836,9 @@ ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status)
|
||||
/* XXX what should we dow now? */
|
||||
}
|
||||
|
||||
if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, UMCR_RTS)
|
||||
if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, SER_RTS)
|
||||
&& !(tp->t_state & TS_TBLOCK))
|
||||
ucomctl(sc, UMCR_RTS, DMBIS);
|
||||
ucommodem(tp, SER_RTS, 0);
|
||||
}
|
||||
|
||||
Static void
|
||||
|
@ -104,10 +104,6 @@ struct ucom_callback {
|
||||
void (*ucom_write)(void *, int, u_char *, u_char *, u_int32_t *);
|
||||
};
|
||||
|
||||
/* modem control register */
|
||||
#define UMCR_RTS 0x02 /* Request To Send */
|
||||
#define UMCR_DTR 0x01 /* Data Terminal Ready */
|
||||
|
||||
/* line status register */
|
||||
#define ULSR_RCV_FIFO 0x80
|
||||
#define ULSR_TSRE 0x40 /* Transmitter empty: byte sent */
|
||||
@ -119,17 +115,6 @@ struct ucom_callback {
|
||||
#define ULSR_RXRDY 0x01 /* Byte ready in Receive Buffer */
|
||||
#define ULSR_RCV_MASK 0x1f /* Mask for incoming data or error */
|
||||
|
||||
/* modem status register */
|
||||
/* All deltas are from the last read of the MSR. */
|
||||
#define UMSR_DCD 0x80 /* Current Data Carrier Detect */
|
||||
#define UMSR_RI 0x40 /* Current Ring Indicator */
|
||||
#define UMSR_DSR 0x20 /* Current Data Set Ready */
|
||||
#define UMSR_CTS 0x10 /* Current Clear to Send */
|
||||
#define UMSR_DDCD 0x08 /* DCD has changed state */
|
||||
#define UMSR_TERI 0x04 /* RI has toggled low to high */
|
||||
#define UMSR_DDSR 0x02 /* DSR has changed state */
|
||||
#define UMSR_DCTS 0x01 /* CTS has changed state */
|
||||
|
||||
/* ucom state declarations */
|
||||
#define UCS_RXSTOP 0x0001 /* Rx stopped */
|
||||
#define UCS_RTS_IFLOW 0x0008 /* use RTS input flow control */
|
||||
@ -168,7 +153,6 @@ struct ucom_softc {
|
||||
u_char sc_msr;
|
||||
u_char sc_mcr;
|
||||
|
||||
u_char sc_opening; /* lock during open */
|
||||
int sc_refcnt;
|
||||
u_char sc_dying; /* disconnecting */
|
||||
|
||||
|
@ -85,6 +85,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/module.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/select.h>
|
||||
@ -515,11 +516,11 @@ umodem_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
|
||||
mstatus = sc->sc_notify_buf.data[0];
|
||||
|
||||
if (ISSET(mstatus, UCDC_N_SERIAL_RI))
|
||||
sc->sc_msr |= UMSR_RI;
|
||||
sc->sc_msr |= SER_RI;
|
||||
if (ISSET(mstatus, UCDC_N_SERIAL_DSR))
|
||||
sc->sc_msr |= UMSR_DSR;
|
||||
sc->sc_msr |= SER_DSR;
|
||||
if (ISSET(mstatus, UCDC_N_SERIAL_DCD))
|
||||
sc->sc_msr |= UMSR_DCD;
|
||||
sc->sc_msr |= SER_DCD;
|
||||
ucom_status_change(&sc->sc_ucom);
|
||||
break;
|
||||
default:
|
||||
|
@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/file.h>
|
||||
#if __FreeBSD_version >= 500014
|
||||
@ -799,9 +800,9 @@ uplcom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
|
||||
sc->sc_lsr = sc->sc_msr = 0;
|
||||
pstatus = buf[8];
|
||||
if (ISSET(pstatus, RSAQ_STATUS_DSR))
|
||||
sc->sc_msr |= UMSR_DSR;
|
||||
sc->sc_msr |= SER_DSR;
|
||||
if (ISSET(pstatus, RSAQ_STATUS_DCD))
|
||||
sc->sc_msr |= UMSR_DCD;
|
||||
sc->sc_msr |= SER_DCD;
|
||||
ucom_status_change(&sc->sc_ucom);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/module.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/serial.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/file.h>
|
||||
#if defined(__FreeBSD__)
|
||||
@ -897,11 +898,11 @@ uvscom_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
|
||||
|
||||
pstatus = buf[1];
|
||||
if (ISSET(pstatus, UVSCOM_CTS))
|
||||
SET(sc->sc_msr, UMSR_CTS);
|
||||
SET(sc->sc_msr, SER_CTS);
|
||||
if (ISSET(pstatus, UVSCOM_DSR))
|
||||
SET(sc->sc_msr, UMSR_DSR);
|
||||
SET(sc->sc_msr, SER_DSR);
|
||||
if (ISSET(pstatus, UVSCOM_DCD))
|
||||
SET(sc->sc_msr, UMSR_DCD);
|
||||
SET(sc->sc_msr, SER_DCD);
|
||||
|
||||
ucom_status_change(&sc->sc_ucom);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user