diff options
author | takawata <takawata@FreeBSD.org> | 2008-09-12 20:34:12 +0000 |
---|---|---|
committer | takawata <takawata@FreeBSD.org> | 2008-09-12 20:34:12 +0000 |
commit | d24ab9bd6fd0e1cf09f7a08b56ca6c02a58b7b10 (patch) | |
tree | be67d71447f0c64c27300df99066fdcfdc9b9906 /sys/dev/usb | |
parent | 272de45514a55fc4a9e4b584a3b04be91b5ac7bc (diff) | |
download | FreeBSD-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.c | 165 |
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); } |