Don't issue CDC request before negotiate the interface role.

This commit is contained in:
takawata 2008-09-12 20:34:12 +00:00
parent 272de45514
commit d24ab9bd6f

View File

@ -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;
uByte c;
x = spltty();
if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)){
ttwwakeup(tp);
return;
}
int len,i;
unsigned char buf[128];
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);
uByte c;
if(ucom->sc_dying)
return;
if(ucom->sc_state &UCS_TXBUSY)
return;
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);
}