summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authortakawata <takawata@FreeBSD.org>2008-09-12 20:34:12 +0000
committertakawata <takawata@FreeBSD.org>2008-09-12 20:34:12 +0000
commitd24ab9bd6fd0e1cf09f7a08b56ca6c02a58b7b10 (patch)
treebe67d71447f0c64c27300df99066fdcfdc9b9906 /sys/dev/usb
parent272de45514a55fc4a9e4b584a3b04be91b5ac7bc (diff)
downloadFreeBSD-src-d24ab9bd6fd0e1cf09f7a08b56ca6c02a58b7b10.zip
FreeBSD-src-d24ab9bd6fd0e1cf09f7a08b56ca6c02a58b7b10.tar.gz
Don't issue CDC request before negotiate the interface role.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/ufoma.c165
1 files changed, 107 insertions, 58 deletions
diff --git a/sys/dev/usb/ufoma.c b/sys/dev/usb/ufoma.c
index 250f161..99100db 100644
--- a/sys/dev/usb/ufoma.c
+++ b/sys/dev/usb/ufoma.c
@@ -148,9 +148,9 @@ typedef struct ufoma_mobile_acm_descriptor{
#define UFOMA_MAX_TIMEOUT 15 /*Standard says 10(sec)*/
#define UFOMA_CMD_BUF_SIZE 64
-#define UMODEMIBUFSIZE 64
-#define UMODEMOBUFSIZE 256
-#define DPRINTF(a)
+#define UMODEMIBUFSIZE 1024
+#define UMODEMOBUFSIZE 1024
+#define DPRINTF(a)
struct ufoma_softc{
struct ucom_softc sc_ucom;
@@ -165,6 +165,7 @@ struct ufoma_softc{
int sc_cm_cap;
int sc_acm_cap;
usb_cdc_line_state_t sc_line_state; /* current line state */
+ usb_cdc_line_state_t sc_line_state_init; /* pre open line state*/
u_char sc_dtr; /* current DTR state */
u_char sc_rts; /* current RTS state */
@@ -196,9 +197,10 @@ static int ufoma_str_to_mode(char *);
#ifdef UFOMA_HANDSFREE
/*Pseudo ucom stuff(for Handsfree interface)*/
static int ufoma_init_pseudo_ucom(struct ufoma_softc *);
-static t_open_t ufomaopen;
-static t_close_t ufomaclose;
-static t_oproc_t ufomastart;
+static tsw_open_t ufoma_open;
+static tsw_close_t ufoma_close;
+static tsw_outwakeup_t ufoma_outwakeup;
+static tsw_free_t ufoma_free;
#endif
/*umodem like stuff*/
@@ -216,17 +218,14 @@ static void ufoma_rts(struct ufoma_softc *sc, int onoff);
static int ufoma_sysctl_support(SYSCTL_HANDLER_ARGS);
static int ufoma_sysctl_current(SYSCTL_HANDLER_ARGS);
static int ufoma_sysctl_open(SYSCTL_HANDLER_ARGS);
-
+static void ufoma_set_line_state(struct ufoma_softc *sc);
static struct ucom_callback ufoma_callback = {
- ufoma_get_status,
- ufoma_set,
- ufoma_param,
- NULL,
- ufoma_ucom_open,
- ufoma_ucom_close,
- NULL,
- NULL,
+ .ucom_get_status = ufoma_get_status,
+ .ucom_set = ufoma_set,
+ .ucom_param = ufoma_param,
+ .ucom_open = ufoma_ucom_open,
+ .ucom_close = ufoma_ucom_close,
};
@@ -395,7 +394,6 @@ ufoma_attach(device_t self)
}
}
elements = mad->bFunctionLength - sizeof(*mad)+1;
-
sc->sc_msgxf = usbd_alloc_xfer(ucom->sc_udev);
sc->sc_nummsg = 0;
@@ -405,6 +403,7 @@ ufoma_attach(device_t self)
bcopy(mad->bMode, &sc->sc_modetable[1], elements);
sc->sc_currentmode = UMCPC_ACM_MODE_UNLINKED;
sc->sc_modetoactivate = mad->bMode[0];
+
/*Sysctls*/
sctx = device_get_sysctl_ctx(self);
soid = device_get_sysctl_tree(self);
@@ -420,6 +419,7 @@ ufoma_attach(device_t self)
SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode",
CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open,
"A", "Mode to transit when port is opened");
+
return 0;
error:
if(sc->sc_modetable)
@@ -442,7 +442,8 @@ ufoma_detach(device_t self)
}
#ifdef UFOMA_HANDSFREE
else{
- ttyfree(sc->sc_ucom.sc_tty);
+ tty_lock(sc->sc_ucom.sc_tty);
+ tty_rel_gone(sc->sc_ucom.sc_tty);
}
#endif
@@ -509,15 +510,16 @@ static int ufoma_link_state(struct ufoma_softc *sc)
usb_device_request_t req;
struct ucom_softc *ucom = &sc->sc_ucom;
int err;
-
+
req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
req.bRequest = UMCPC_SET_LINK;
USETW(req.wValue, UMCPC_CM_MOBILE_ACM);
USETW(req.wIndex, sc->sc_ctl_iface_no);
USETW(req.wLength, sc->sc_modetable[0]);
+
err = usbd_do_request(ucom->sc_udev, &req, sc->sc_modetable);
if(err){
- printf("SET_LINK:%d\n", err);
+ printf("SET_LINK:%s\n",usbd_errstr(err));
return EIO;
}
err = tsleep(&sc->sc_currentmode, PZERO|PCATCH, "fmalnk", hz);
@@ -581,9 +583,15 @@ static void ufoma_msg(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_stat
ufoma_setup_msg_req(sc, &req);
mtx_lock(&sc->sc_mtx);
for(i = 0;i < actlen; i++){
- if(sc->sc_ucom.sc_tty->t_state & TS_ISOPEN)
- ttyld_rint(sc->sc_ucom.sc_tty, sc->sc_resbuffer[i]);
+
+ if(ttydisc_rint(sc->sc_ucom.sc_tty, sc->sc_resbuffer[i], 0)
+ == -1){
+ break;
+ }
}
+
+ ttydisc_rint_done(sc->sc_ucom.sc_tty);
+
sc->sc_nummsg--;
if(sc->sc_nummsg){
usbd_setup_default_xfer(sc->sc_msgxf, ucom->sc_udev,
@@ -603,6 +611,7 @@ static void ufoma_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_sta
unsigned int a;
struct ucom_softc *ucom =&sc->sc_ucom;
u_char mstatus;
+
#ifdef UFOMA_HANDSFREE
usb_device_request_t req;
@@ -689,27 +698,33 @@ static void ufoma_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_sta
}
#ifdef UFOMA_HANDSFREE
+struct ttydevsw ufomatty_class ={
+ .tsw_flags = TF_INITLOCK|TF_CALLOUT,
+ .tsw_open = ufoma_open,
+ .tsw_close = ufoma_close,
+ .tsw_outwakeup = ufoma_outwakeup,
+ .tsw_free = ufoma_free
+};
+static void ufoma_free(void *sc)
+{
+
+}
static int ufoma_init_pseudo_ucom(struct ufoma_softc *sc)
{
struct tty *tp;
struct ucom_softc *ucom = &sc->sc_ucom;
- tp = ucom->sc_tty = ttyalloc();
- tp->t_sc = sc;
- tp->t_oproc = ufomastart;
- tp->t_stop = nottystop;
- tp->t_open = ufomaopen;
- tp->t_close = ufomaclose;
- ttycreate(tp, TS_CALLOUT, "U%d", device_get_unit(ucom->sc_dev));
+ tp = ucom->sc_tty = tty_alloc(&ufomatty_class, sc, &Giant);
+ tty_makedev(tp, NULL, "U%d", device_get_unit(ucom->sc_dev));
return 0;
}
-static int ufomaopen(struct tty * tty, struct cdev *cdev)
+static int ufoma_open(struct tty * tty)
{
- struct ufoma_softc *sc = tty->t_sc;
-
+ struct ufoma_softc *sc = tty_softc(tty);
+
if(sc->sc_ucom.sc_dying)
return (ENXIO);
@@ -723,38 +738,46 @@ static int ufomaopen(struct tty * tty, struct cdev *cdev)
return ufoma_ucom_open(sc, 0);
}
-static void ufomaclose(struct tty *tty)
+static void ufoma_close(struct tty *tty)
{
- struct ufoma_softc *sc = tty->t_sc;
+ struct ufoma_softc *sc = tty_softc(tty);
+
ufoma_ucom_close(sc, 0);
}
-static void ufomastart(struct tty *tp)
+static void ufoma_outwakeup(struct tty *tp)
{
- struct ufoma_softc *sc = tp->t_sc;
+ struct ufoma_softc *sc = tty_softc(tp);
struct ucom_softc *ucom = &sc->sc_ucom;
usb_device_request_t req;
- int x;
+ int len,i;
+ unsigned char buf[128];
+
uByte c;
- x = spltty();
- if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)){
- ttwwakeup(tp);
+ if(ucom->sc_dying)
+ return;
+ if(ucom->sc_state &UCS_TXBUSY)
return;
- }
- tp->t_state |= TS_BUSY;
- while(tp->t_outq.c_cc != 0){
- c = getc(&tp->t_outq);
- req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
- req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
- USETW(req.wIndex, sc->sc_ctl_iface_no);
- USETW(req.wValue, 0);
- USETW(req.wLength, 1);
- usbd_do_request(ucom->sc_udev, &req, &c);
+ ucom->sc_state |= UCS_TXBUSY;
+ for(;;){
+ len = ttydisc_getc(tp, buf, sizeof(buf));
+ if(len == 0){
+ break;
+ }
+
+ for(i=0; i < len; i++){
+ req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
+ c = buf[i];
+ req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
+ USETW(req.wIndex, sc->sc_ctl_iface_no);
+ USETW(req.wValue, 0);
+ USETW(req.wLength, 1);
+ usbd_do_request(ucom->sc_udev, &req, &c);
+ }
}
- tp->t_state &= ~TS_BUSY;
- ttwwakeup(tp);
- splx(x);
+ ucom->sc_state |= UCS_TXBUSY;
+
}
#endif
@@ -762,14 +785,28 @@ static void ufomastart(struct tty *tp)
static int ufoma_ucom_open(void *p, int portno)
{
struct ufoma_softc *sc = p;
+ int res;
+
if(sc->sc_currentmode == UMCPC_ACM_MODE_UNLINKED){
- ufoma_link_state(sc);
+ if((res = ufoma_link_state(sc))){
+ return res;
+ }
}
+
sc->sc_cmdbp = 0;
if(sc->sc_currentmode == UMCPC_ACM_MODE_DEACTIVATED){
- ufoma_activate_state(sc, sc->sc_modetoactivate);
+ if((res = ufoma_activate_state(sc, sc->sc_modetoactivate))){
+ return res;
+ }
+ }
+ mtx_lock(&sc->sc_mtx);
+ sc->sc_isopen = 1;
+ mtx_unlock(&sc->sc_mtx);
+ /*Now line coding should be set.*/
+ if(sc->sc_is_ucom){
+ ufoma_set_line_state(sc);
+ ufoma_set_line_coding(sc, NULL);
}
-
return 0;
}
@@ -777,6 +814,9 @@ static void ufoma_ucom_close(void *p, int portno)
{
struct ufoma_softc *sc = p;
ufoma_activate_state(sc, UMCPC_ACM_MODE_DEACTIVATED);
+ mtx_lock(&sc->sc_mtx);
+ sc->sc_isopen = 0;
+ mtx_unlock(&sc->sc_mtx);
return ;
}
@@ -837,6 +877,10 @@ ufoma_set_line_state(struct ufoma_softc *sc)
struct ucom_softc *ucom = &sc->sc_ucom;
int ls;
+ if(!sc->sc_isopen){
+ return ; /*Set it later*/
+ }
+
ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
(sc->sc_rts ? UCDC_LINE_RTS : 0);
req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
@@ -880,12 +924,17 @@ ufoma_set_line_coding(struct ufoma_softc *sc, usb_cdc_line_state_t *state)
usbd_status err;
usb_device_request_t req;
struct ucom_softc *ucom = &sc->sc_ucom;
-
+ if(!sc->sc_isopen){
+ sc->sc_line_state_init = *state;
+ return (USBD_NORMAL_COMPLETION);
+ }
DPRINTF(("ufoma_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
UGETDW(state->dwDTERate), state->bCharFormat,
state->bParityType, state->bDataBits));
-
- if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
+ if(state == NULL){
+ state = &sc->sc_line_state_init;
+ }else if (memcmp(state, &sc->sc_line_state,
+ UCDC_LINE_STATE_LENGTH) == 0) {
DPRINTF(("ufoma_set_line_coding: already set\n"));
return (USBD_NORMAL_COMPLETION);
}
OpenPOWER on IntegriCloud