xref: /netbsd-src/sys/dev/usb/uberry.c (revision 1e72df6a037fdd3c6d3014a2679ffff7daab84ca)
1*1e72df6aStsutsui /*	$NetBSD: uberry.c,v 1.16 2019/12/15 16:48:27 tsutsui Exp $	*/
22b96eb72Schristos 
32b96eb72Schristos /*-
42b96eb72Schristos  * Copyright (c) 2008 The NetBSD Foundation, Inc.
52b96eb72Schristos  * All rights reserved.
62b96eb72Schristos  *
72b96eb72Schristos  * This code is derived from software contributed to The NetBSD Foundation
82b96eb72Schristos  * by Christos Zoulas.
92b96eb72Schristos  *
102b96eb72Schristos  * Redistribution and use in source and binary forms, with or without
112b96eb72Schristos  * modification, are permitted provided that the following conditions
122b96eb72Schristos  * are met:
132b96eb72Schristos  * 1. Redistributions of source code must retain the above copyright
142b96eb72Schristos  *    notice, this list of conditions and the following disclaimer.
152b96eb72Schristos  * 2. Redistributions in binary form must reproduce the above copyright
162b96eb72Schristos  *    notice, this list of conditions and the following disclaimer in the
172b96eb72Schristos  *    documentation and/or other materials provided with the distribution.
182b96eb72Schristos  *
192b96eb72Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
202b96eb72Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
212b96eb72Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
222b96eb72Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
232b96eb72Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242b96eb72Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252b96eb72Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262b96eb72Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272b96eb72Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282b96eb72Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292b96eb72Schristos  * POSSIBILITY OF SUCH DAMAGE.
302b96eb72Schristos  */
312b96eb72Schristos 
322b96eb72Schristos #include <sys/cdefs.h>
33*1e72df6aStsutsui __KERNEL_RCSID(0, "$NetBSD: uberry.c,v 1.16 2019/12/15 16:48:27 tsutsui Exp $");
34a7c71d30Sskrll 
35a7c71d30Sskrll #ifdef _KERNEL_OPT
36a7c71d30Sskrll #include "opt_usb.h"
37a7c71d30Sskrll #endif
382b96eb72Schristos 
392b96eb72Schristos #include <sys/param.h>
402b96eb72Schristos #include <sys/systm.h>
412b96eb72Schristos #include <sys/kernel.h>
422b96eb72Schristos #include <sys/device.h>
432b96eb72Schristos #include <sys/ioctl.h>
442b96eb72Schristos #include <sys/conf.h>
452b96eb72Schristos #include <sys/file.h>
462b96eb72Schristos #include <sys/select.h>
472b96eb72Schristos #include <sys/proc.h>
482b96eb72Schristos #include <sys/vnode.h>
492b96eb72Schristos #include <sys/poll.h>
50b14ecf8eSjmcneill #include <sys/bus.h>
512b96eb72Schristos 
522b96eb72Schristos #include <dev/usb/usb.h>
532b96eb72Schristos #include <dev/usb/usbdi.h>
542b96eb72Schristos #include <dev/usb/usbdi_util.h>
55b14ecf8eSjmcneill #include <dev/usb/usbdivar.h>
562b96eb72Schristos 
572b96eb72Schristos #include <dev/usb/usbdevs.h>
582b96eb72Schristos 
592b96eb72Schristos #ifdef UBERRY_DEBUG
6049337c88Sdyoung #define DPRINTF(x)	if (uberrydebug) printf x
6149337c88Sdyoung #define DPRINTFN(n, x)	if (uberrydebug > n) printf x
622b96eb72Schristos int	uberrydebug = 0;
632b96eb72Schristos #else
642b96eb72Schristos #define DPRINTF(x)
652b96eb72Schristos #define DPRINTFN(n, x)
662b96eb72Schristos #endif
672b96eb72Schristos 
682b96eb72Schristos struct uberry_softc {
6949337c88Sdyoung 	device_t		sc_dev;
704e8e6643Sskrll 	struct usbd_device *	sc_udev;
712b96eb72Schristos };
722b96eb72Schristos 
7307b705dfSjmcneill /*
7407b705dfSjmcneill  * Note that we do not attach to USB_PRODUCT_RIM_BLACKBERRY_PEARL_DUAL
7507b705dfSjmcneill  * as we let umass claim the device instead.
7607b705dfSjmcneill  */
772b96eb72Schristos static const struct usb_devno uberry_devs[] = {
782b96eb72Schristos 	{ USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY },
792b96eb72Schristos 	{ USB_VENDOR_RIM, USB_PRODUCT_RIM_BLACKBERRY_PEARL },
802b96eb72Schristos };
812b96eb72Schristos 
822b96eb72Schristos #define uberry_lookup(v, p) usb_lookup(uberry_devs, v, p)
832b96eb72Schristos #define UBERRY_CONFIG_NO 1
842b96eb72Schristos 
8597b908dcSmaxv static int	uberry_match(device_t, cfdata_t, void *);
8697b908dcSmaxv static void	uberry_attach(device_t, device_t, void *);
8797b908dcSmaxv static int	uberry_detach(device_t, int);
883b24a134Smrg 
897a2bcc80Sdyoung CFATTACH_DECL_NEW(uberry, sizeof(struct uberry_softc), uberry_match,
907a2bcc80Sdyoung     uberry_attach, uberry_detach, NULL);
912b96eb72Schristos 
922b96eb72Schristos static void
uberry_cmd(struct uberry_softc * sc,uint8_t requestType,uint8_t reqno,uint8_t value,uint8_t index,void * data,uint8_t length)932b96eb72Schristos uberry_cmd(struct uberry_softc *sc, uint8_t requestType, uint8_t reqno,
942b96eb72Schristos     uint8_t value, uint8_t index, void *data, uint8_t length)
952b96eb72Schristos {
962b96eb72Schristos 	usb_device_request_t req;
972b96eb72Schristos 	usbd_status err;
982b96eb72Schristos 
992b96eb72Schristos 	DPRINTF(("berry cmd type=%x, number=%x, value=%d, index=%d, len=%d\n",
1002b96eb72Schristos 	    requestType, reqno, value, index, length));
1012b96eb72Schristos         req.bmRequestType = requestType;
1022b96eb72Schristos         req.bRequest = reqno;
1032b96eb72Schristos         USETW(req.wValue, value);
1042b96eb72Schristos         USETW(req.wIndex, index);
1052b96eb72Schristos         USETW(req.wLength, length);
1062b96eb72Schristos 
1072b96eb72Schristos         if ((err = usbd_do_request(sc->sc_udev, &req, data)) != 0)
1082b96eb72Schristos 		aprint_error_dev(sc->sc_dev, "sending command failed %d\n",
1092b96eb72Schristos 		    err);
1102b96eb72Schristos }
1112b96eb72Schristos 
1122b96eb72Schristos static void
uberry_charge(struct uberry_softc * sc)1132b96eb72Schristos uberry_charge(struct uberry_softc *sc)
1142b96eb72Schristos {
1152b96eb72Schristos 	char dummy[2];
116b14ecf8eSjmcneill 	usbd_status err;
1172b96eb72Schristos 
1184e8e6643Sskrll 	if (sc->sc_udev->ud_power != USB_MAX_POWER) {
1192b96eb72Schristos 		uberry_cmd(sc, UT_READ | UT_VENDOR, 0xa5, 0, 1, dummy, 2);
1202b96eb72Schristos 		uberry_cmd(sc, UT_WRITE | UT_VENDOR, 0xa2, 0, 1, dummy, 0);
12107b705dfSjmcneill 	}
122b14ecf8eSjmcneill 
123b14ecf8eSjmcneill 	err = usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1);
124b14ecf8eSjmcneill 	if (err) {
125897388eaSskrll 		aprint_error_dev(sc->sc_dev, "failed to set configuration"
126897388eaSskrll 		    ", err=%s\n", usbd_errstr(err));
12707b705dfSjmcneill 		return;
128b14ecf8eSjmcneill 	}
1292b96eb72Schristos }
1302b96eb72Schristos 
1312b96eb72Schristos /*
1322b96eb72Schristos  * Expose both the USB mass storage interface and the database access one
1332b96eb72Schristos  */
1342b96eb72Schristos static void
uberry_dual_mode(struct uberry_softc * sc)1352b96eb72Schristos uberry_dual_mode(struct uberry_softc *sc)
1362b96eb72Schristos {
1372b96eb72Schristos 	char dummy[2];
138b14ecf8eSjmcneill 	usbd_status err;
1392b96eb72Schristos 
1402b96eb72Schristos 	uberry_cmd(sc, UT_READ | UT_VENDOR, 0xa9, 1, 1, dummy, 2);
141b14ecf8eSjmcneill 
142b14ecf8eSjmcneill 	err = usbd_set_config_no(sc->sc_udev, UBERRY_CONFIG_NO, 1);
143b14ecf8eSjmcneill 	if (err) {
144897388eaSskrll 		aprint_error_dev(sc->sc_dev, "failed to set configuration"
145897388eaSskrll 		    ", err=%s\n", usbd_errstr(err));
14607b705dfSjmcneill 		return;
147b14ecf8eSjmcneill 	}
1482b96eb72Schristos }
1492b96eb72Schristos 
1502b96eb72Schristos 
15197b908dcSmaxv static int
uberry_match(device_t parent,cfdata_t match,void * aux)1527a2bcc80Sdyoung uberry_match(device_t parent, cfdata_t match, void *aux)
1532b96eb72Schristos {
1547a2bcc80Sdyoung 	struct usb_attach_arg *uaa = aux;
1552b96eb72Schristos 
1562b96eb72Schristos 	DPRINTFN(50, ("uberry_match\n"));
1574e8e6643Sskrll 	return (uberry_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ?
1582b96eb72Schristos 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
1592b96eb72Schristos }
1602b96eb72Schristos 
16197b908dcSmaxv static void
uberry_attach(device_t parent,device_t self,void * aux)1627a2bcc80Sdyoung uberry_attach(device_t parent, device_t self, void *aux)
1632b96eb72Schristos {
1647a2bcc80Sdyoung 	struct uberry_softc *sc = device_private(self);
1657a2bcc80Sdyoung 	struct usb_attach_arg *uaa = aux;
1664e8e6643Sskrll 	struct usbd_device *	dev = uaa->uaa_device;
1672b96eb72Schristos 	char			*devinfop;
1682b96eb72Schristos 
1692b96eb72Schristos 	DPRINTFN(10,("uberry_attach: sc=%p\n", sc));
1702b96eb72Schristos 
1712b96eb72Schristos 	sc->sc_dev = self;
1722b96eb72Schristos 	sc->sc_udev = dev;
1732b96eb72Schristos 
1745fab894cSplunky 	aprint_naive("\n");
1755fab894cSplunky 	aprint_normal("\n");
1765fab894cSplunky 
1772b96eb72Schristos 	devinfop = usbd_devinfo_alloc(dev, 0);
1782b96eb72Schristos 	aprint_normal_dev(self, "%s\n", devinfop);
1792b96eb72Schristos 	usbd_devinfo_free(devinfop);
1802b96eb72Schristos 
1812b96eb72Schristos 	uberry_charge(sc);
1824e8e6643Sskrll 	if (uaa->uaa_product == USB_PRODUCT_RIM_BLACKBERRY_PEARL)
1832b96eb72Schristos 		uberry_dual_mode(sc);
1842b96eb72Schristos 
1852b96eb72Schristos 	DPRINTFN(10, ("uberry_attach: %p\n", sc->sc_udev));
1862b96eb72Schristos 
18707b705dfSjmcneill 	if (!pmf_device_register(self, NULL, NULL))
18807b705dfSjmcneill 		aprint_error_dev(self, "couldn't establish power handler\n");
18907b705dfSjmcneill 
1907a2bcc80Sdyoung 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
1917a2bcc80Sdyoung 	return;
1922b96eb72Schristos }
1932b96eb72Schristos 
19497b908dcSmaxv static int
uberry_detach(device_t self,int flags)1957a2bcc80Sdyoung uberry_detach(device_t self, int flags)
1962b96eb72Schristos {
1977a2bcc80Sdyoung 	struct uberry_softc *sc = device_private(self);
1982b96eb72Schristos 	DPRINTF(("uberry_detach: sc=%p flags=%d\n", sc, flags));
19907b705dfSjmcneill 
20007b705dfSjmcneill 	pmf_device_deregister(self);
2012b96eb72Schristos 
2027a2bcc80Sdyoung 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
2032b96eb72Schristos 
20426ee7ba1Sskrll 	return 0;
2052b96eb72Schristos }
206