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