Exemple #1
0
void
umodem_attach(struct device *parent, struct device *self, void *aux)
{
    struct umodem_softc *sc = (struct umodem_softc *)self;
    struct usb_attach_arg *uaa = aux;
    struct usbd_device *dev = uaa->device;
    usb_interface_descriptor_t *id;
    usb_endpoint_descriptor_t *ed;
    usbd_status err;
    int data_iface_idx = -1;
    int i;
    struct ucom_attach_args uca;

    sc->sc_udev = dev;
    sc->sc_ctl_iface = uaa->iface;

    id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
    //printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname,
    //    id->bInterfaceClass, id->bInterfaceSubClass);
    sc->sc_ctl_iface_no = id->bInterfaceNumber;

    /* Get the capabilities. */
    umodem_get_caps(uaa, id->bInterfaceNumber, &data_iface_idx,
                    &sc->sc_cm_cap, &sc->sc_acm_cap);

    usbd_claim_iface(sc->sc_udev, data_iface_idx);
    sc->sc_data_iface = uaa->ifaces[data_iface_idx];
    id = usbd_get_interface_descriptor(sc->sc_data_iface);

    printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
           sc->sc_dev.dv_xname, id->bInterfaceNumber,
           sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
           sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");

    /*
     * Find the bulk endpoints.
     * Iterate over all endpoints in the data interface and take note.
     */
    uca.bulkin = uca.bulkout = -1;

    for (i = 0; i < id->bNumEndpoints; i++) {
        ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
        if (ed == NULL) {
            printf("%s: no endpoint descriptor for %d\n",
                   sc->sc_dev.dv_xname, i);
            goto bad;
        }
        if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
            uca.bulkin = ed->bEndpointAddress;
        } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
                   (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
            uca.bulkout = ed->bEndpointAddress;
        }
    }

    if (uca.bulkin == -1) {
        printf("%s: Could not find data bulk in\n",
               sc->sc_dev.dv_xname);
        goto bad;
    }
    if (uca.bulkout == -1) {
        printf("%s: Could not find data bulk out\n",
               sc->sc_dev.dv_xname);
        goto bad;
    }

    if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) {
        sc->sc_cm_over_data = 1;
    } else {
        if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) {
            if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE)
                err = umodem_set_comm_feature(sc,
                                              UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED);
            else
                err = 0;
            if (err) {
                printf("%s: could not set data multiplex mode\n",
                       sc->sc_dev.dv_xname);
                goto bad;
            }
            sc->sc_cm_over_data = 1;
        }
    }

    /*
     * The standard allows for notification messages (to indicate things
     * like a modem hangup) to come in via an interrupt endpoint
     * off of the control interface.  Iterate over the endpoints on
     * the control interface and see if there are any interrupt
     * endpoints; if there are, then register it.
     */

    sc->sc_ctl_notify = -1;
    sc->sc_notify_pipe = NULL;

    id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
    for (i = 0; i < id->bNumEndpoints; i++) {
        ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
        if (ed == NULL)
            continue;

        if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
                (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
            printf("%s: status change notification available\n",
                   sc->sc_dev.dv_xname);
            sc->sc_ctl_notify = ed->bEndpointAddress;
        }
    }

    sc->sc_dtr = -1;

    uca.portno = UCOM_UNK_PORTNO;
    /* bulkin, bulkout set above */
    uca.ibufsize = UMODEMIBUFSIZE;
    uca.obufsize = UMODEMOBUFSIZE;
    uca.ibufsizepad = UMODEMIBUFSIZE;
    uca.opkthdrlen = 0;
    uca.device = sc->sc_udev;
    uca.iface = sc->sc_data_iface;
    uca.methods = &umodem_methods;
    uca.arg = sc;
    uca.info = NULL;

    DPRINTF(("umodem_attach: sc=%p\n", sc));
    sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);

    return;

bad:
    usbd_deactivate(sc->sc_udev);
}
Exemple #2
0
static int
umodem_attach(device_t self)
{
	struct umodem_softc *sc = device_get_softc(self);
	struct usb_attach_arg *uaa = device_get_ivars(self);
	usbd_device_handle dev = uaa->device;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	const char *devname;
	usbd_status err;
	int data_ifcno;
	int i;
	struct ucom_softc *ucom;

	ucom = &sc->sc_ucom;
	ucom->sc_dev = self;
	sc->sc_dev = self;
	ucom->sc_udev = dev;
	ucom->sc_iface = uaa->iface;

	sc->sc_udev = dev;
	sc->sc_ctl_iface = uaa->iface;

	devname = device_get_nameunit(sc->sc_dev);
	/* XXX ? use something else ? XXX */
	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
	sc->sc_ctl_iface_no = id->bInterfaceNumber;

	sc->sc_data_iface_no = data_ifcno =
		umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap, id);

	if (data_ifcno == -1) {
		kprintf("%s: no pointer to data interface\n", devname);
		goto bad;
	}

	kprintf("%s: data interface %d, has %sCM over data, has %sbreak\n",
	       devname, data_ifcno,
	       sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
	       sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");

	/* Get the data interface too. */
	for (i = 0; i < uaa->nifaces; i++) {
		if (uaa->ifaces[i] != NULL) {
			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
			if (id != NULL && id->bInterfaceNumber == data_ifcno) {
				sc->sc_data_iface = uaa->ifaces[i];
				uaa->ifaces[i] = NULL;
			}
		}
	}
	if (sc->sc_data_iface == NULL) {
		kprintf("%s: no data interface\n", devname);
		goto bad;
	}
	ucom->sc_iface = sc->sc_data_iface;

	/*
	 * Find the bulk endpoints.
	 * Iterate over all endpoints in the data interface and take note.
	 */
	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;

	id = usbd_get_interface_descriptor(sc->sc_data_iface);
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
		if (ed == NULL) {
			kprintf("%s: no endpoint descriptor for %d\n", devname,
			    i);
			goto bad;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			ucom->sc_bulkin_no = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			ucom->sc_bulkout_no = ed->bEndpointAddress;
		}
	}

	if (ucom->sc_bulkin_no == -1) {
		kprintf("%s: Could not find data bulk in\n", devname);
		goto bad;
	}
	if (ucom->sc_bulkout_no == -1) {
		kprintf("%s: Could not find data bulk out\n", devname);
		goto bad;
	}

	if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) {
		DPRINTF(("Quirk says to assume CM over data\n"));
		sc->sc_cm_over_data = 1;
	} else {
		if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) {
			if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE)
				err = umodem_set_comm_feature(sc,
				    UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED);
			else
				err = 0;
			if (err) {
				kprintf("%s: could not set data multiplex mode\n",
				    devname);
				goto bad;
			}
			sc->sc_cm_over_data = 1;
		}
	}

	/*
	 * The standard allows for notification messages (to indicate things
	 * like a modem hangup) to come in via an interrupt endpoint
	 * off of the control interface.  Iterate over the endpoints on
	 * the control interface and see if there are any interrupt
	 * endpoints; if there are, then register it.
	 */

	sc->sc_ctl_notify = -1;
	sc->sc_notify_pipe = NULL;

	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
		if (ed == NULL)
			continue;

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
			kprintf("%s: status change notification available\n",
			    devname);
			sc->sc_ctl_notify = ed->bEndpointAddress;
		}
	}

	sc->sc_dtr = -1;

	ucom->sc_parent = sc;
	ucom->sc_portno = UCOM_UNK_PORTNO;
	/* bulkin, bulkout set above */
	ucom->sc_ibufsize = UMODEMIBUFSIZE;
	ucom->sc_obufsize = UMODEMOBUFSIZE;
	ucom->sc_ibufsizepad = UMODEMIBUFSIZE;
	ucom->sc_opkthdrlen = 0;
	ucom->sc_callback = &umodem_callback;

	ucom_attach(&sc->sc_ucom);

	return 0;

 bad:
	ucom->sc_dying = 1;
	return ENXIO;
}
void
umodem_attach(struct device *parent, struct device *self, void *aux)
{
	struct umodem_softc *sc = (struct umodem_softc *)self;
	struct usb_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	usb_cdc_cm_descriptor_t *cmd;      
	usb_interface_descriptor_t *idesc;
	const usb_cdc_acm_descriptor_t *acmd;
	const usb_cdc_union_descriptor_t *uniond;
	const usb_descriptor_t *desc;
	usbd_desc_iter_t iter;
	usbd_status err;
	int current_iface_no = -1;
	int i;
	struct ucom_attach_args uca;

	sc->sc_udev = dev;
	sc->sc_ctl_iface = uaa->iface;

	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
	//printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname,
	//    id->bInterfaceClass, id->bInterfaceSubClass);
	sc->sc_ctl_iface_no = id->bInterfaceNumber;

	/* Get the data interface no. and capabilities */
	sc->sc_cm_cap = 0;
	sc->sc_data_iface_no = 0;
	sc->sc_acm_cap = 0;
	usb_desc_iter_init(dev, &iter);
	desc = usb_desc_iter_next(&iter);
	while (desc) {
		if (desc->bDescriptorType == UDESC_INTERFACE) {
		    idesc = (usb_interface_descriptor_t *)desc;
		    current_iface_no = idesc->bInterfaceNumber;
		}
		if (current_iface_no == sc->sc_ctl_iface_no &&
		    desc->bDescriptorType == UDESC_CS_INTERFACE) {
			switch(desc->bDescriptorSubtype) {
			case UDESCSUB_CDC_CM:
				cmd = (usb_cdc_cm_descriptor_t *)desc;
				sc->sc_cm_cap = cmd->bmCapabilities;
				sc->sc_data_iface_no = cmd->bDataInterface;
				break;
			case UDESCSUB_CDC_ACM:
				acmd = (usb_cdc_acm_descriptor_t *)desc;
				sc->sc_acm_cap = acmd->bmCapabilities;
				break;
			case UDESCSUB_CDC_UNION:
				uniond = (usb_cdc_union_descriptor_t *)desc;
				sc->sc_data_iface_no =
				    uniond->bSlaveInterface[0];
				break;
			}
		}
		desc = usb_desc_iter_next(&iter);
	}

	if (sc->sc_data_iface_no == 0) {
		printf("%s: no pointer to data interface\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}

	printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
	       sc->sc_dev.dv_xname, sc->sc_data_iface_no,
	       sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
	       sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");

	/* Get the data interface too. */
	for (i = 0; i < uaa->nifaces; i++) {
		if (uaa->ifaces[i] != NULL) {
			id = usbd_get_interface_descriptor(uaa->ifaces[i]);
			if (id != NULL &&
                            id->bInterfaceNumber == sc->sc_data_iface_no) {
				sc->sc_data_iface = uaa->ifaces[i];
				uaa->ifaces[i] = NULL;
			}
		}
	}
	if (sc->sc_data_iface == NULL) {
		printf("%s: no data interface\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	/*
	 * Find the bulk endpoints.
	 * Iterate over all endpoints in the data interface and take note.
	 */
	uca.bulkin = uca.bulkout = -1;

	id = usbd_get_interface_descriptor(sc->sc_data_iface);
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
				sc->sc_dev.dv_xname, i);
			goto bad;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
                        uca.bulkin = ed->bEndpointAddress;
                } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) {
                        uca.bulkout = ed->bEndpointAddress;
                }
        }

	if (uca.bulkin == -1) {
		printf("%s: Could not find data bulk in\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}
	if (uca.bulkout == -1) {
		printf("%s: Could not find data bulk out\n",
			sc->sc_dev.dv_xname);
		goto bad;
	}

	if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) {
		sc->sc_cm_over_data = 1;
	} else {
		if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) {
			if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE)
				err = umodem_set_comm_feature(sc,
				    UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED);
			else
				err = 0;
			if (err) {
				printf("%s: could not set data multiplex mode\n",
				       sc->sc_dev.dv_xname);
				goto bad;
			}
			sc->sc_cm_over_data = 1;
		}
	}

	/*
	 * The standard allows for notification messages (to indicate things
	 * like a modem hangup) to come in via an interrupt endpoint
	 * off of the control interface.  Iterate over the endpoints on
	 * the control interface and see if there are any interrupt
	 * endpoints; if there are, then register it.
	 */

	sc->sc_ctl_notify = -1;
	sc->sc_notify_pipe = NULL;

	id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
		if (ed == NULL)
			continue;

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
			printf("%s: status change notification available\n",
			       sc->sc_dev.dv_xname);
			sc->sc_ctl_notify = ed->bEndpointAddress;
		}
	}

	sc->sc_dtr = -1;

	uca.portno = UCOM_UNK_PORTNO;
	/* bulkin, bulkout set above */
	uca.ibufsize = UMODEMIBUFSIZE;
	uca.obufsize = UMODEMOBUFSIZE;
	uca.ibufsizepad = UMODEMIBUFSIZE;
	uca.opkthdrlen = 0;
	uca.device = sc->sc_udev;
	uca.iface = sc->sc_data_iface;
	uca.methods = &umodem_methods;
	uca.arg = sc;
	uca.info = NULL;

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   &sc->sc_dev);

	DPRINTF(("umodem_attach: sc=%p\n", sc));
	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);

	return;

 bad:
	sc->sc_dying = 1;
}