summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/serial/usb_serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/serial/usb_serial.c')
-rw-r--r--sys/dev/usb/serial/usb_serial.c188
1 files changed, 75 insertions, 113 deletions
diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c
index 5404bd8..d185977 100644
--- a/sys/dev/usb/serial/usb_serial.c
+++ b/sys/dev/usb/serial/usb_serial.c
@@ -123,13 +123,16 @@ static unsigned int ucom_cons_tx_low = 0;
static unsigned int ucom_cons_tx_high = 0;
static int ucom_cons_unit = -1;
+static int ucom_cons_subunit = 0;
static int ucom_cons_baud = 9600;
static struct ucom_softc *ucom_cons_softc = NULL;
TUNABLE_INT("hw.usb.ucom.cons_unit", &ucom_cons_unit);
SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_unit, CTLFLAG_RW,
&ucom_cons_unit, 0, "console unit number");
-
+TUNABLE_INT("hw.usb.ucom.cons_subunit", &ucom_cons_subunit);
+SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_subunit, CTLFLAG_RW,
+ &ucom_cons_subunit, 0, "console subunit number");
TUNABLE_INT("hw.usb.ucom.cons_baud", &ucom_cons_baud);
SYSCTL_INT(_hw_usb_ucom, OID_AUTO, cons_baud, CTLFLAG_RW,
&ucom_cons_baud, 0, "console baud rate");
@@ -141,9 +144,9 @@ static usb_proc_callback_t ucom_cfg_line_state;
static usb_proc_callback_t ucom_cfg_status_change;
static usb_proc_callback_t ucom_cfg_param;
-static uint8_t ucom_units_alloc(uint32_t, uint32_t *);
-static void ucom_units_free(uint32_t, uint32_t);
-static int ucom_attach_tty(struct ucom_softc *, uint32_t);
+static int ucom_unit_alloc(void);
+static void ucom_unit_free(int);
+static int ucom_attach_tty(struct ucom_super_softc *, struct ucom_softc *);
static void ucom_detach_tty(struct ucom_softc *);
static void ucom_queue_command(struct ucom_softc *,
usb_proc_callback_t *, struct termios *pt,
@@ -176,84 +179,52 @@ static struct ttydevsw ucom_class = {
MODULE_DEPEND(ucom, usb, 1, 1, 1);
MODULE_VERSION(ucom, 1);
-#define UCOM_UNIT_MAX 0x200 /* exclusive */
-#define UCOM_SUB_UNIT_MAX 0x100 /* exclusive */
+#define UCOM_UNIT_MAX 128 /* limits size of ucom_bitmap */
static uint8_t ucom_bitmap[(UCOM_UNIT_MAX + 7) / 8];
static struct mtx ucom_bitmap_mtx;
MTX_SYSINIT(ucom_bitmap_mtx, &ucom_bitmap_mtx, "ucom bitmap", MTX_DEF);
-static uint8_t
-ucom_units_alloc(uint32_t sub_units, uint32_t *p_root_unit)
+/*
+ * Mark a unit number (the X in cuaUX) as in use.
+ *
+ * Note that devices using a different naming scheme (see ucom_tty_name()
+ * callback) still use this unit allocation.
+ */
+static int
+ucom_unit_alloc(void)
{
- uint32_t n;
- uint32_t o;
- uint32_t x;
- uint32_t max = UCOM_UNIT_MAX - (UCOM_UNIT_MAX % sub_units);
- uint8_t error = 1;
+ int unit;
mtx_lock(&ucom_bitmap_mtx);
- for (n = 0; n < max; n += sub_units) {
-
- /* check for free consecutive bits */
-
- for (o = 0; o < sub_units; o++) {
-
- x = n + o;
-
- if (ucom_bitmap[x / 8] & (1 << (x % 8))) {
- goto skip;
- }
- }
-
- /* allocate */
-
- for (o = 0; o < sub_units; o++) {
-
- x = n + o;
-
- ucom_bitmap[x / 8] |= (1 << (x % 8));
- }
-
- error = 0;
-
- break;
-
-skip: ;
- }
+ for (unit = 0; unit < UCOM_UNIT_MAX; unit++)
+ if ((ucom_bitmap[unit / 8] & (1 << (unit % 8))) == 0)
+ break;
mtx_unlock(&ucom_bitmap_mtx);
- /*
- * Always set the variable pointed to by "p_root_unit" so that
- * the compiler does not think that it is used uninitialised:
- */
- *p_root_unit = n;
-
- return (error);
+ if (unit == UCOM_UNIT_MAX)
+ return -1;
+ else
+ return unit;
}
+/*
+ * Mark the unit number as not in use.
+ */
static void
-ucom_units_free(uint32_t root_unit, uint32_t sub_units)
+ucom_unit_free(int unit)
{
- uint32_t x;
-
mtx_lock(&ucom_bitmap_mtx);
- while (sub_units--) {
- x = root_unit + sub_units;
- ucom_bitmap[x / 8] &= ~(1 << (x % 8));
- }
+ ucom_bitmap[unit / 8] &= ~(1 << (unit % 8));
mtx_unlock(&ucom_bitmap_mtx);
}
/*
- * "N" sub_units are setup at a time. All sub-units will
- * be given sequential unit numbers. The number of
- * sub-units can be used to differentiate among
- * different types of devices.
+ * Setup a group of one or more serial ports.
*
* The mutex pointed to by "mtx" is applied before all
* callbacks are called back. Also "mtx" must be applied
@@ -261,47 +232,47 @@ ucom_units_free(uint32_t root_unit, uint32_t sub_units)
*/
int
ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
- uint32_t sub_units, void *parent,
+ uint32_t subunits, void *parent,
const struct ucom_callback *callback, struct mtx *mtx)
{
- uint32_t n;
- uint32_t root_unit;
+ uint32_t subunit;
int error = 0;
if ((sc == NULL) ||
- (sub_units == 0) ||
- (sub_units > UCOM_SUB_UNIT_MAX) ||
+ (subunits == 0) ||
(callback == NULL)) {
return (EINVAL);
}
- /* XXX unit management does not really belong here */
- if (ucom_units_alloc(sub_units, &root_unit)) {
+ ssc->sc_unit = ucom_unit_alloc();
+ if (ssc->sc_unit == -1)
return (ENOMEM);
- }
error = usb_proc_create(&ssc->sc_tq, mtx, "ucom", USB_PRI_MED);
if (error) {
- ucom_units_free(root_unit, sub_units);
+ ucom_unit_free(ssc->sc_unit);
return (error);
}
+ ssc->sc_subunits = subunits;
- for (n = 0; n != sub_units; n++, sc++) {
- sc->sc_unit = root_unit + n;
- sc->sc_local_unit = n;
- sc->sc_super = ssc;
- sc->sc_mtx = mtx;
- sc->sc_parent = parent;
- sc->sc_callback = callback;
+ for (subunit = 0; subunit != ssc->sc_subunits; subunit++) {
+ sc[subunit].sc_subunit = subunit;
+ sc[subunit].sc_super = ssc;
+ sc[subunit].sc_mtx = mtx;
+ sc[subunit].sc_parent = parent;
+ sc[subunit].sc_callback = callback;
- error = ucom_attach_tty(sc, sub_units);
+ error = ucom_attach_tty(ssc, &sc[subunit]);
if (error) {
- ucom_detach(ssc, sc - n, n);
- ucom_units_free(root_unit + n, sub_units - n);
+ ucom_detach(ssc, &sc[0]);
return (error);
}
- sc->sc_flag |= UCOM_FLAG_ATTACHED;
+ sc[subunit].sc_flag |= UCOM_FLAG_ATTACHED;
}
+
+ DPRINTF("tp = %p, unit = %d, subunits = %d, device name subunit 0 = %s\n",
+ sc->sc_tty, ssc->sc_unit, ssc->sc_subunits, sc[0].sc_devname);
+
return (0);
}
@@ -310,62 +281,50 @@ ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
* the structure pointed to by "ssc" and "sc" is zero.
*/
void
-ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc,
- uint32_t sub_units)
+ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
{
- uint32_t n;
+ uint32_t subunit;
usb_proc_drain(&ssc->sc_tq);
- for (n = 0; n != sub_units; n++, sc++) {
- if (sc->sc_flag & UCOM_FLAG_ATTACHED) {
-
- ucom_detach_tty(sc);
+ for (subunit = 0; subunit <= ssc->sc_subunits; subunit++) {
+ if (sc[subunit].sc_flag & UCOM_FLAG_ATTACHED) {
- ucom_units_free(sc->sc_unit, 1);
+ ucom_detach_tty(&sc[subunit]);
- /* avoid duplicate detach: */
- sc->sc_flag &= ~UCOM_FLAG_ATTACHED;
+ /* avoid duplicate detach */
+ sc[subunit].sc_flag &= ~UCOM_FLAG_ATTACHED;
}
}
+ ucom_unit_free(ssc->sc_unit);
usb_proc_free(&ssc->sc_tq);
}
static int
-ucom_attach_tty(struct ucom_softc *sc, uint32_t sub_units)
+ucom_attach_tty(struct ucom_super_softc *ssc, struct ucom_softc *sc)
{
struct tty *tp;
- int error = 0;
- char buf[32]; /* temporary TTY device name buffer */
+ char buf[10]; /* temporary TTY device name buffer */
tp = tty_alloc_mutex(&ucom_class, sc, sc->sc_mtx);
- if (tp == NULL) {
- error = ENOMEM;
- goto done;
- }
- DPRINTF("tp = %p, unit = %d\n", tp, sc->sc_unit);
-
- buf[0] = 0; /* set some default value */
+ if (tp == NULL)
+ return (ENOMEM);
/* Check if the client has a custom TTY name */
+ buf[0] = '\0';
if (sc->sc_callback->ucom_tty_name) {
sc->sc_callback->ucom_tty_name(sc, buf,
- sizeof(buf), sc->sc_local_unit);
+ sizeof(buf), ssc->sc_unit, sc->sc_subunit);
}
if (buf[0] == 0) {
/* Use default TTY name */
- if (sub_units > 1) {
+ if (ssc->sc_subunits > 1) {
/* multiple modems in one */
- if (snprintf(buf, sizeof(buf), "U%u.%u",
- sc->sc_unit - sc->sc_local_unit,
- sc->sc_local_unit)) {
- /* ignore */
- }
+ snprintf(buf, sizeof(buf), "U%u.%u",
+ ssc->sc_unit, sc->sc_subunit);
} else {
/* single modem */
- if (snprintf(buf, sizeof(buf), "U%u", sc->sc_unit)) {
- /* ignore */
- }
+ snprintf(buf, sizeof(buf), "U%u", ssc->sc_unit);
}
}
tty_makedev(tp, NULL, "%s", buf);
@@ -377,10 +336,12 @@ ucom_attach_tty(struct ucom_softc *sc, uint32_t sub_units)
/* Check if this device should be a console */
if ((ucom_cons_softc == NULL) &&
- (sc->sc_unit == ucom_cons_unit)) {
-
+ (ssc->sc_unit == ucom_cons_unit) &&
+ (sc->sc_subunit == ucom_cons_subunit)) {
struct termios t;
+ DPRINTF("unit %d subunit %d is console", ssc->sc_unit, sc->sc_subunit);
+
ucom_cons_softc = sc;
memset(&t, 0, sizeof(t));
@@ -398,8 +359,8 @@ ucom_attach_tty(struct ucom_softc *sc, uint32_t sub_units)
ucom_param(ucom_cons_softc->sc_tty, &t);
mtx_unlock(ucom_cons_softc->sc_mtx);
}
-done:
- return (error);
+
+ return (0);
}
static void
@@ -412,6 +373,7 @@ ucom_detach_tty(struct ucom_softc *sc)
if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
mtx_lock(ucom_cons_softc->sc_mtx);
ucom_close(ucom_cons_softc->sc_tty);
+ sc->sc_flag &= ~UCOM_FLAG_CONSOLE;
mtx_unlock(ucom_cons_softc->sc_mtx);
ucom_cons_softc = NULL;
}
OpenPOWER on IntegriCloud