1*a4d9265cSmanu /* $NetBSD: umodeswitch.c,v 1.6 2023/08/04 13:25:17 manu Exp $ */
288e04a21Schristos
388e04a21Schristos /*-
488e04a21Schristos * Copyright (c) 2009, 2017 The NetBSD Foundation, Inc.
588e04a21Schristos * All rights reserved.
688e04a21Schristos *
788e04a21Schristos * This code is derived from software contributed to The NetBSD Foundation.
888e04a21Schristos *
988e04a21Schristos * Redistribution and use in source and binary forms, with or without
1088e04a21Schristos * modification, are permitted provided that the following conditions
1188e04a21Schristos * are met:
1288e04a21Schristos * 1. Redistributions of source code must retain the above copyright
1388e04a21Schristos * notice, this list of conditions and the following disclaimer.
1488e04a21Schristos * 2. Redistributions in binary form must reproduce the above copyright
1588e04a21Schristos * notice, this list of conditions and the following disclaimer in the
1688e04a21Schristos * documentation and/or other materials provided with the distribution.
1788e04a21Schristos *
1888e04a21Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1988e04a21Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2088e04a21Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2188e04a21Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2288e04a21Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2388e04a21Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2488e04a21Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2588e04a21Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2688e04a21Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2788e04a21Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2888e04a21Schristos * POSSIBILITY OF SUCH DAMAGE.
2988e04a21Schristos */
3088e04a21Schristos
3188e04a21Schristos
3288e04a21Schristos #include <sys/cdefs.h>
33*a4d9265cSmanu __KERNEL_RCSID(0, "$NetBSD: umodeswitch.c,v 1.6 2023/08/04 13:25:17 manu Exp $");
3488e04a21Schristos
3588e04a21Schristos #include <sys/param.h>
3688e04a21Schristos #include <sys/systm.h>
3788e04a21Schristos #include <sys/kernel.h>
3888e04a21Schristos #include <sys/kmem.h>
3988e04a21Schristos #include <sys/bus.h>
4088e04a21Schristos #include <sys/conf.h>
4188e04a21Schristos #include <sys/tty.h>
4288e04a21Schristos
4388e04a21Schristos #include <dev/usb/usb.h>
4488e04a21Schristos #include <dev/usb/usbdi.h>
4588e04a21Schristos #include <dev/usb/usbdivar.h>
4688e04a21Schristos #include <dev/usb/usbdi_util.h>
4788e04a21Schristos
4888e04a21Schristos #include "usbdevs.h"
4988e04a21Schristos
5088e04a21Schristos /*
5188e04a21Schristos * This device driver handles devices that have two personalities.
5288e04a21Schristos * The first uses the 'usbdevif'
5388e04a21Schristos * interface attribute so that a match will claim the entire USB device
5488e04a21Schristos * for itself. This is used for when a device needs to be mode-switched
5588e04a21Schristos * and ensures any other interfaces present cannot be claimed by other
5688e04a21Schristos * drivers while the mode-switch is in progress.
5788e04a21Schristos */
5888e04a21Schristos static int umodeswitch_match(device_t, cfdata_t, void *);
5988e04a21Schristos static void umodeswitch_attach(device_t, device_t, void *);
6088e04a21Schristos static int umodeswitch_detach(device_t, int);
6188e04a21Schristos
6288e04a21Schristos CFATTACH_DECL2_NEW(umodeswitch, 0, umodeswitch_match,
6388e04a21Schristos umodeswitch_attach, umodeswitch_detach, NULL, NULL, NULL);
6488e04a21Schristos
6588e04a21Schristos static int
send_bulkmsg(struct usbd_device * dev,void * cmd,size_t cmdlen)6688e04a21Schristos send_bulkmsg(struct usbd_device *dev, void *cmd, size_t cmdlen)
6788e04a21Schristos {
6888e04a21Schristos struct usbd_interface *iface;
6988e04a21Schristos usb_interface_descriptor_t *id;
7088e04a21Schristos usb_endpoint_descriptor_t *ed;
7188e04a21Schristos struct usbd_pipe *pipe;
7288e04a21Schristos struct usbd_xfer *xfer;
7388e04a21Schristos int err, i;
7488e04a21Schristos
7588e04a21Schristos /* Move the device into the configured state. */
7688e04a21Schristos err = usbd_set_config_index(dev, 0, 0);
7788e04a21Schristos if (err) {
7888e04a21Schristos aprint_error("%s: failed to set config index\n", __func__);
7988e04a21Schristos return UMATCH_NONE;
8088e04a21Schristos }
8188e04a21Schristos
8288e04a21Schristos err = usbd_device2interface_handle(dev, 0, &iface);
8388e04a21Schristos if (err != 0) {
8488e04a21Schristos aprint_error("%s: failed to get interface\n", __func__);
8588e04a21Schristos return UMATCH_NONE;
8688e04a21Schristos }
8788e04a21Schristos
8888e04a21Schristos id = usbd_get_interface_descriptor(iface);
8988e04a21Schristos ed = NULL;
9088e04a21Schristos for (i = 0 ; i < id->bNumEndpoints ; i++) {
9188e04a21Schristos ed = usbd_interface2endpoint_descriptor(iface, i);
9288e04a21Schristos if (ed == NULL)
9388e04a21Schristos continue;
9488e04a21Schristos if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_OUT)
9588e04a21Schristos continue;
9688e04a21Schristos if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK)
9788e04a21Schristos break;
9888e04a21Schristos }
9988e04a21Schristos
10088e04a21Schristos if (i == id->bNumEndpoints)
10188e04a21Schristos return UMATCH_NONE;
10288e04a21Schristos
10388e04a21Schristos err = usbd_open_pipe(iface, ed->bEndpointAddress,
10488e04a21Schristos USBD_EXCLUSIVE_USE, &pipe);
10588e04a21Schristos if (err != 0) {
10688e04a21Schristos aprint_error("%s: failed to open bulk transfer pipe %d\n",
10788e04a21Schristos __func__, ed->bEndpointAddress);
10888e04a21Schristos return UMATCH_NONE;
10988e04a21Schristos }
11088e04a21Schristos
11188e04a21Schristos int error = usbd_create_xfer(pipe, cmdlen, 0, 0, &xfer);
11288e04a21Schristos if (!error) {
11388e04a21Schristos
11488e04a21Schristos usbd_setup_xfer(xfer, NULL, cmd, cmdlen,
11588e04a21Schristos USBD_SYNCHRONOUS, USBD_DEFAULT_TIMEOUT, NULL);
11688e04a21Schristos
11788e04a21Schristos err = usbd_transfer(xfer);
11888e04a21Schristos
11988e04a21Schristos #if 0 /* XXXpooka: at least my huawei "fails" this always, but still detaches */
12088e04a21Schristos if (err)
12188e04a21Schristos aprint_error("%s: transfer failed\n", __func__);
12288e04a21Schristos #else
12388e04a21Schristos err = 0;
12488e04a21Schristos #endif
12588e04a21Schristos usbd_destroy_xfer(xfer);
12688e04a21Schristos } else {
12788e04a21Schristos aprint_error("%s: failed to allocate xfer\n", __func__);
12888e04a21Schristos err = USBD_NOMEM;
12988e04a21Schristos }
13088e04a21Schristos
13188e04a21Schristos usbd_abort_pipe(pipe);
13288e04a21Schristos usbd_close_pipe(pipe);
13388e04a21Schristos
13488e04a21Schristos return err == USBD_NORMAL_COMPLETION ? UMATCH_HIGHEST : UMATCH_NONE;
13588e04a21Schristos }
13688e04a21Schristos
13788e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
13888e04a21Schristos static void
set_cbw(unsigned char * cmd)13988e04a21Schristos set_cbw(unsigned char *cmd)
14088e04a21Schristos {
14188e04a21Schristos cmd[0] = 0x55;
14288e04a21Schristos cmd[1] = 0x53;
14388e04a21Schristos cmd[2] = 0x42;
14488e04a21Schristos cmd[3] = 0x43;
14588e04a21Schristos }
14688e04a21Schristos
14788e04a21Schristos static int
u3g_bulk_scsi_eject(struct usbd_device * dev)14888e04a21Schristos u3g_bulk_scsi_eject(struct usbd_device *dev)
14988e04a21Schristos {
15088e04a21Schristos unsigned char cmd[31];
15188e04a21Schristos
15288e04a21Schristos memset(cmd, 0, sizeof(cmd));
15388e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
15488e04a21Schristos set_cbw(cmd);
15588e04a21Schristos /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
15688e04a21Schristos cmd[4] = 0x01;
15788e04a21Schristos /* 8..11: CBW Transfer Length, no data here */
15888e04a21Schristos /* 12: CBW Flag: output, so 0 */
15988e04a21Schristos /* 13: CBW Lun: 0 */
16088e04a21Schristos /* 14: CBW Length */
16188e04a21Schristos cmd[14] = 0x06;
16288e04a21Schristos
16388e04a21Schristos /* Rest is the SCSI payload */
16488e04a21Schristos
16588e04a21Schristos /* 0: SCSI START/STOP opcode */
16688e04a21Schristos cmd[15] = 0x1b;
16788e04a21Schristos /* 1..3 unused */
16888e04a21Schristos /* 4 Load/Eject command */
16988e04a21Schristos cmd[19] = 0x02;
17088e04a21Schristos /* 5: unused */
17188e04a21Schristos
17288e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
17388e04a21Schristos }
17488e04a21Schristos
17588e04a21Schristos static int
u3g_bulk_ata_eject(struct usbd_device * dev)17688e04a21Schristos u3g_bulk_ata_eject(struct usbd_device *dev)
17788e04a21Schristos {
17888e04a21Schristos unsigned char cmd[31];
17988e04a21Schristos
18088e04a21Schristos memset(cmd, 0, sizeof(cmd));
18188e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
18288e04a21Schristos set_cbw(cmd);
18388e04a21Schristos /* 4..7: CBW Tag, has to unique, but only a single transfer used. */
18488e04a21Schristos cmd[4] = 0x01;
18588e04a21Schristos /* 8..11: CBW Transfer Length, no data here */
18688e04a21Schristos /* 12: CBW Flag: output, so 0 */
18788e04a21Schristos /* 13: CBW Lun: 0 */
18888e04a21Schristos /* 14: CBW Length */
18988e04a21Schristos cmd[14] = 0x06;
19088e04a21Schristos
19188e04a21Schristos /* Rest is the SCSI payload */
19288e04a21Schristos
19388e04a21Schristos /* 0: ATA pass-through */
19488e04a21Schristos cmd[15] = 0x85;
19588e04a21Schristos /* 1..3 unused */
19688e04a21Schristos /* 4 XXX What is this command? */
19788e04a21Schristos cmd[19] = 0x24;
19888e04a21Schristos /* 5: unused */
19988e04a21Schristos
20088e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
20188e04a21Schristos }
20288e04a21Schristos
20388e04a21Schristos static int
u3g_huawei_reinit(struct usbd_device * dev)20488e04a21Schristos u3g_huawei_reinit(struct usbd_device *dev)
20588e04a21Schristos {
20688e04a21Schristos /*
20788e04a21Schristos * The Huawei device presents itself as a umass device with Windows
20888e04a21Schristos * drivers on it. After installation of the driver, it reinits into a
20988e04a21Schristos * 3G serial device.
21088e04a21Schristos */
21188e04a21Schristos usb_device_request_t req;
21288e04a21Schristos usb_config_descriptor_t *cdesc;
21388e04a21Schristos
21488e04a21Schristos /* Get the config descriptor */
21588e04a21Schristos cdesc = usbd_get_config_descriptor(dev);
21688e04a21Schristos if (cdesc == NULL) {
21788e04a21Schristos usb_device_descriptor_t dd;
21888e04a21Schristos
21988e04a21Schristos if (usbd_get_device_desc(dev, &dd) != 0)
22088e04a21Schristos return UMATCH_NONE;
22188e04a21Schristos
22288e04a21Schristos if (dd.bNumConfigurations != 1)
22388e04a21Schristos return UMATCH_NONE;
22488e04a21Schristos
22588e04a21Schristos if (usbd_set_config_index(dev, 0, 1) != 0)
22688e04a21Schristos return UMATCH_NONE;
22788e04a21Schristos
22888e04a21Schristos cdesc = usbd_get_config_descriptor(dev);
22988e04a21Schristos
23088e04a21Schristos if (cdesc == NULL)
23188e04a21Schristos return UMATCH_NONE;
23288e04a21Schristos }
23388e04a21Schristos
23488e04a21Schristos /*
23588e04a21Schristos * One iface means umass mode, more than 1 (4 usually) means 3G mode.
23688e04a21Schristos *
23788e04a21Schristos * XXX: We should check the first interface's device class just to be
23888e04a21Schristos * sure. If it's a mass storage device, then we can be fairly certain
23988e04a21Schristos * it needs a mode-switch.
24088e04a21Schristos */
24188e04a21Schristos if (cdesc->bNumInterface > 1)
24288e04a21Schristos return UMATCH_NONE;
24388e04a21Schristos
24488e04a21Schristos req.bmRequestType = UT_WRITE_DEVICE;
24588e04a21Schristos req.bRequest = UR_SET_FEATURE;
24688e04a21Schristos USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
24788e04a21Schristos USETW(req.wIndex, UHF_PORT_SUSPEND);
24888e04a21Schristos USETW(req.wLength, 0);
24988e04a21Schristos
25088e04a21Schristos (void) usbd_do_request(dev, &req, 0);
25188e04a21Schristos
25288e04a21Schristos return UMATCH_HIGHEST; /* Prevent umass from attaching */
25388e04a21Schristos }
25488e04a21Schristos
25588e04a21Schristos static int
u3g_huawei_k3765_reinit(struct usbd_device * dev)25688e04a21Schristos u3g_huawei_k3765_reinit(struct usbd_device *dev)
25788e04a21Schristos {
25888e04a21Schristos unsigned char cmd[31];
25988e04a21Schristos
26088e04a21Schristos /* magic string adapted from some webpage */
26188e04a21Schristos memset(cmd, 0, sizeof(cmd));
26288e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
26388e04a21Schristos set_cbw(cmd);
26488e04a21Schristos
26588e04a21Schristos cmd[15]= 0x11;
26688e04a21Schristos cmd[16]= 0x06;
26788e04a21Schristos
26888e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
26988e04a21Schristos }
27088e04a21Schristos static int
u3g_huawei_e171_reinit(struct usbd_device * dev)27188e04a21Schristos u3g_huawei_e171_reinit(struct usbd_device *dev)
27288e04a21Schristos {
27388e04a21Schristos unsigned char cmd[31];
27488e04a21Schristos
27588e04a21Schristos /* magic string adapted from some webpage */
27688e04a21Schristos memset(cmd, 0, sizeof(cmd));
27788e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
27888e04a21Schristos set_cbw(cmd);
27988e04a21Schristos
28088e04a21Schristos cmd[15]= 0x11;
28188e04a21Schristos cmd[16]= 0x06;
28288e04a21Schristos cmd[17]= 0x20;
28388e04a21Schristos cmd[20]= 0x01;
28488e04a21Schristos
28588e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
28688e04a21Schristos }
28788e04a21Schristos
28888e04a21Schristos static int
u3g_huawei_e353_reinit(struct usbd_device * dev)28988e04a21Schristos u3g_huawei_e353_reinit(struct usbd_device *dev)
29088e04a21Schristos {
29188e04a21Schristos unsigned char cmd[31];
29288e04a21Schristos
29388e04a21Schristos /* magic string adapted from some webpage */
29488e04a21Schristos memset(cmd, 0, sizeof(cmd));
29588e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
29688e04a21Schristos set_cbw(cmd);
29788e04a21Schristos
29888e04a21Schristos cmd[4] = 0x7f;
29988e04a21Schristos cmd[9] = 0x02;
30088e04a21Schristos cmd[12] = 0x80;
30188e04a21Schristos cmd[14] = 0x0a;
30288e04a21Schristos cmd[15] = 0x11;
30388e04a21Schristos cmd[16] = 0x06;
30488e04a21Schristos cmd[17] = 0x20;
30588e04a21Schristos cmd[23] = 0x01;
30688e04a21Schristos
30788e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
30888e04a21Schristos }
30988e04a21Schristos
31088e04a21Schristos static int
u3g_sierra_reinit(struct usbd_device * dev)31188e04a21Schristos u3g_sierra_reinit(struct usbd_device *dev)
31288e04a21Schristos {
31388e04a21Schristos /* Some Sierra devices presents themselves as a umass device with
31488e04a21Schristos * Windows drivers on it. After installation of the driver, it
31588e04a21Schristos * reinits into a * 3G serial device.
31688e04a21Schristos */
31788e04a21Schristos usb_device_request_t req;
31888e04a21Schristos
31988e04a21Schristos req.bmRequestType = UT_VENDOR;
32088e04a21Schristos req.bRequest = UR_SET_INTERFACE;
32188e04a21Schristos USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP);
32288e04a21Schristos USETW(req.wIndex, UHF_PORT_CONNECTION);
32388e04a21Schristos USETW(req.wLength, 0);
32488e04a21Schristos
32588e04a21Schristos (void) usbd_do_request(dev, &req, 0);
32688e04a21Schristos
32788e04a21Schristos return UMATCH_HIGHEST; /* Match to prevent umass from attaching */
32888e04a21Schristos }
32988e04a21Schristos
33088e04a21Schristos static int
u3g_4gsystems_reinit(struct usbd_device * dev)33188e04a21Schristos u3g_4gsystems_reinit(struct usbd_device *dev)
33288e04a21Schristos {
33388e04a21Schristos /* magic string adapted from usb_modeswitch database */
33488e04a21Schristos unsigned char cmd[31];
33588e04a21Schristos
33688e04a21Schristos memset(cmd, 0, sizeof(cmd));
33788e04a21Schristos /* Byte 0..3: Command Block Wrapper (CBW) signature */
33888e04a21Schristos set_cbw(cmd);
33988e04a21Schristos
34088e04a21Schristos cmd[4] = 0x12;
34188e04a21Schristos cmd[5] = 0x34;
34288e04a21Schristos cmd[6] = 0x56;
34388e04a21Schristos cmd[7] = 0x78;
34488e04a21Schristos cmd[8] = 0x80;
34588e04a21Schristos cmd[12] = 0x80;
34688e04a21Schristos cmd[14] = 0x06;
34788e04a21Schristos cmd[15] = 0x06;
34888e04a21Schristos cmd[16] = 0xf5;
34988e04a21Schristos cmd[17] = 0x04;
35088e04a21Schristos cmd[18] = 0x02;
35188e04a21Schristos cmd[19] = 0x52;
35288e04a21Schristos cmd[20] = 0x70;
35388e04a21Schristos
35488e04a21Schristos return send_bulkmsg(dev, cmd, sizeof(cmd));
35588e04a21Schristos }
35688e04a21Schristos
35788e04a21Schristos /*
35888e04a21Schristos * First personality:
35988e04a21Schristos *
36088e04a21Schristos * Claim the entire device if a mode-switch is required.
36188e04a21Schristos */
36288e04a21Schristos
36388e04a21Schristos static int
umodeswitch_match(device_t parent,cfdata_t match,void * aux)36488e04a21Schristos umodeswitch_match(device_t parent, cfdata_t match, void *aux)
36588e04a21Schristos {
36688e04a21Schristos struct usb_attach_arg *uaa = aux;
36788e04a21Schristos
36888e04a21Schristos /*
36988e04a21Schristos * Huawei changes product when it is configured as a modem.
37088e04a21Schristos */
37188e04a21Schristos switch (uaa->uaa_vendor) {
37288e04a21Schristos case USB_VENDOR_HUAWEI:
37388e04a21Schristos if (uaa->uaa_product == USB_PRODUCT_HUAWEI_K3765)
37488e04a21Schristos return UMATCH_NONE;
37588e04a21Schristos
37688e04a21Schristos switch (uaa->uaa_product) {
37788e04a21Schristos case USB_PRODUCT_HUAWEI_E1750INIT:
37888e04a21Schristos case USB_PRODUCT_HUAWEI_K3765INIT:
37988e04a21Schristos return u3g_huawei_k3765_reinit(uaa->uaa_device);
38088e04a21Schristos break;
38188e04a21Schristos case USB_PRODUCT_HUAWEI_E171INIT:
38288e04a21Schristos return u3g_huawei_e171_reinit(uaa->uaa_device);
38388e04a21Schristos break;
38488e04a21Schristos case USB_PRODUCT_HUAWEI_E353INIT:
38588e04a21Schristos return u3g_huawei_e353_reinit(uaa->uaa_device);
38688e04a21Schristos break;
38788e04a21Schristos default:
38888e04a21Schristos return u3g_huawei_reinit(uaa->uaa_device);
38988e04a21Schristos break;
39088e04a21Schristos }
39188e04a21Schristos break;
39288e04a21Schristos
39388e04a21Schristos case USB_VENDOR_NOVATEL2:
39488e04a21Schristos switch (uaa->uaa_product){
39588e04a21Schristos case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
39688e04a21Schristos case USB_PRODUCT_NOVATEL2_U760_DRIVER:
39788e04a21Schristos return u3g_bulk_scsi_eject(uaa->uaa_device);
39888e04a21Schristos break;
39988e04a21Schristos default:
40088e04a21Schristos break;
40188e04a21Schristos }
40288e04a21Schristos break;
40388e04a21Schristos
4042b406972Smsaitoh case USB_VENDOR_LG:
4052b406972Smsaitoh if (uaa->uaa_product == USB_PRODUCT_LG_NTT_DOCOMO_L02C_STORAGE)
40688e04a21Schristos return u3g_bulk_scsi_eject(uaa->uaa_device);
40788e04a21Schristos break;
40888e04a21Schristos
409828ce1d2Skhorben case USB_VENDOR_RALINK:
410828ce1d2Skhorben switch (uaa->uaa_product){
411828ce1d2Skhorben case USB_PRODUCT_RALINK_RT73:
412828ce1d2Skhorben return u3g_bulk_scsi_eject(uaa->uaa_device);
413828ce1d2Skhorben break;
414828ce1d2Skhorben }
415828ce1d2Skhorben break;
416828ce1d2Skhorben
41747c45097Skhorben case USB_VENDOR_SIERRA:
41847c45097Skhorben if (uaa->uaa_product == USB_PRODUCT_SIERRA_INSTALLER)
41947c45097Skhorben return u3g_sierra_reinit(uaa->uaa_device);
42047c45097Skhorben break;
42147c45097Skhorben
42288e04a21Schristos case USB_VENDOR_ZTE:
42388e04a21Schristos switch (uaa->uaa_product){
42488e04a21Schristos case USB_PRODUCT_ZTE_INSTALLER:
42588e04a21Schristos case USB_PRODUCT_ZTE_MF820D_INSTALLER:
42688e04a21Schristos (void)u3g_bulk_ata_eject(uaa->uaa_device);
42788e04a21Schristos (void)u3g_bulk_scsi_eject(uaa->uaa_device);
42888e04a21Schristos return UMATCH_HIGHEST;
42988e04a21Schristos default:
43088e04a21Schristos break;
43188e04a21Schristos }
43288e04a21Schristos break;
43388e04a21Schristos
4342b406972Smsaitoh case USB_VENDOR_LONGCHEER:
4352b406972Smsaitoh if (uaa->uaa_product == USB_PRODUCT_LONGCHEER_XSSTICK_P14_INSTALLER)
43688e04a21Schristos return u3g_4gsystems_reinit(uaa->uaa_device);
43788e04a21Schristos break;
43888e04a21Schristos
43917ba5223Smanu case USB_VENDOR_DLINK:
44017ba5223Smanu switch (uaa->uaa_product) {
44117ba5223Smanu case USB_PRODUCT_DLINK_DWM157E_CD:
44217ba5223Smanu case USB_PRODUCT_DLINK_DWM157_CD:
443*a4d9265cSmanu case USB_PRODUCT_DLINK_DWM222_CD:
44417ba5223Smanu (void)u3g_bulk_ata_eject(uaa->uaa_device);
44517ba5223Smanu (void)u3g_bulk_scsi_eject(uaa->uaa_device);
44617ba5223Smanu return UMATCH_HIGHEST;
44717ba5223Smanu default:
44817ba5223Smanu break;
44917ba5223Smanu }
45017ba5223Smanu
45188e04a21Schristos default:
45288e04a21Schristos break;
45388e04a21Schristos }
45488e04a21Schristos
45588e04a21Schristos return UMATCH_NONE;
45688e04a21Schristos }
45788e04a21Schristos
45888e04a21Schristos static void
umodeswitch_attach(device_t parent,device_t self,void * aux)45988e04a21Schristos umodeswitch_attach(device_t parent, device_t self, void *aux)
46088e04a21Schristos {
46188e04a21Schristos struct usb_attach_arg *uaa = aux;
46288e04a21Schristos
46388e04a21Schristos aprint_naive("\n");
46488e04a21Schristos aprint_normal(": Switching off umass mode\n");
46588e04a21Schristos
46688e04a21Schristos if (uaa->uaa_vendor == USB_VENDOR_NOVATEL2) {
46788e04a21Schristos switch (uaa->uaa_product) {
46888e04a21Schristos case USB_PRODUCT_NOVATEL2_MC950D_DRIVER:
46988e04a21Schristos case USB_PRODUCT_NOVATEL2_U760_DRIVER:
47088e04a21Schristos /* About to disappear... */
47188e04a21Schristos return;
47288e04a21Schristos break;
47388e04a21Schristos default:
47488e04a21Schristos break;
47588e04a21Schristos }
47688e04a21Schristos }
47788e04a21Schristos
47888e04a21Schristos /* Move the device into the configured state. */
47988e04a21Schristos (void) usbd_set_config_index(uaa->uaa_device, 0, 1);
48088e04a21Schristos }
48188e04a21Schristos
48288e04a21Schristos static int
umodeswitch_detach(device_t self,int flags)48388e04a21Schristos umodeswitch_detach(device_t self, int flags)
48488e04a21Schristos {
48588e04a21Schristos
48688e04a21Schristos return 0;
48788e04a21Schristos }
488