b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * Device driver for the Apple Desktop Bus
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) * and the /dev/adb device on macintoshes.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) * Copyright (C) 1996 Paul Mackerras.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) * Modified to declare controllers as structures, added
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * client notification of bus reset and handles PowerBook
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) * sleep, by Benjamin Herrenschmidt.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) * To do:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) * - /sys/bus/adb to list the devices and infos
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) * - more /dev/adb to allow userland to receive the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) * flow of auto-polling datas from a given device.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) * - move bus probe to a kernel thread
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) #include <linux/types.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) #include <linux/errno.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) #include <linux/kernel.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #include <linux/slab.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24) #include <linux/module.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25) #include <linux/fs.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) #include <linux/mm.h>
174cd4b1e5fbd (Ingo Molnar 2017-02-02 19:15:33 +0100 27) #include <linux/sched/signal.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) #include <linux/adb.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) #include <linux/cuda.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) #include <linux/pmu.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) #include <linux/notifier.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) #include <linux/wait.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) #include <linux/init.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) #include <linux/delay.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) #include <linux/spinlock.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) #include <linux/completion.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) #include <linux/device.h>
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 38) #include <linux/kthread.h>
fe2528b96b021 (Geert Uytterhoeven 2008-02-03 16:49:09 +0100 39) #include <linux/platform_device.h>
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 40) #include <linux/mutex.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41)
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 42) #include <linux/uaccess.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 43) #ifdef CONFIG_PPC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) #include <asm/prom.h>
e8222502ee615 (Benjamin Herrenschmidt 2006-03-28 23:15:54 +1100 45) #include <asm/machdep.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 49) EXPORT_SYMBOL(adb_client_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 50)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) extern struct adb_driver via_macii_driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52) extern struct adb_driver via_cuda_driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) extern struct adb_driver adb_iop_driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) extern struct adb_driver via_pmu_driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) extern struct adb_driver macio_adb_driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 57) static DEFINE_MUTEX(adb_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) static struct adb_driver *adb_driver_list[] = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) #ifdef CONFIG_ADB_MACII
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) &via_macii_driver,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) #ifdef CONFIG_ADB_CUDA
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) &via_cuda_driver,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) #ifdef CONFIG_ADB_IOP
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) &adb_iop_driver,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) #endif
ebd722275f9cf (Finn Thain 2018-07-02 04:21:19 -0400 68) #ifdef CONFIG_ADB_PMU
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) &via_pmu_driver,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) #ifdef CONFIG_ADB_MACIO
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) &macio_adb_driver,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) NULL
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76)
56b2293595b2e (Greg Kroah-Hartman 2005-03-23 10:01:41 -0800 77) static struct class *adb_dev_class;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78)
9b4a8dd2e9f8a (Adrian Bunk 2008-06-24 03:46:57 +1000 79) static struct adb_driver *adb_controller;
e041c683412d5 (Alan Stern 2006-03-27 01:16:30 -0800 80) BLOCKING_NOTIFIER_HEAD(adb_client_list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) static int adb_got_sleep;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) static int adb_inited;
8192b1f6b1a46 (Thomas Gleixner 2010-09-07 14:33:40 +0000 83) static DEFINE_SEMAPHORE(adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) static int sleepy_trackpad;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) static int autopoll_devs;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) int __adb_probe_sync;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88) static int adb_scan_bus(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) static int do_adb_reset_bus(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) static void adbdev_init(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) static int try_handler_change(int, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) static struct adb_handler {
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 94) void (*handler)(unsigned char *, int, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) int original_address;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) int handler_id;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) int busy;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) } adb_handler[16];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100) /*
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 101) * The adb_handler_mutex mutex protects all accesses to the original_address
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) * and handler_id fields of adb_handler[i] for all i, and changes to the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 103) * handler field.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104) * Accesses to the handler field are protected by the adb_handler_lock
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) * rwlock. It is held across all calls to any handler, so that by the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 106) * time adb_unregister returns, we know that the old handler isn't being
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 107) * called.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108) */
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 109) static DEFINE_MUTEX(adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) static DEFINE_RWLOCK(adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) #if 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) static void printADBreply(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 116)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) printk("adb reply (%d)", req->reply_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) for(i = 0; i < req->reply_len; i++)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119) printk(" %x", req->reply[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 120) printk("\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 123) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 124)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125) static int adb_scan_bus(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 127) int i, highFree=0, noMovement;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) int devmask = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) /* assumes adb_handler[] is all zeroes at this point */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132) for (i = 1; i < 16; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 133) /* see if there is anything at address i */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 135) (i << 4) | 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 136) if (req.reply_len > 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137) /* one or more devices at this address */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) adb_handler[i].original_address = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139) else if (i > highFree)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140) highFree = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143) /* Note we reset noMovement to 0 each time we move a device */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 144) for (noMovement = 1; noMovement < 2 && highFree > 0; noMovement++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145) for (i = 1; i < 16; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146) if (adb_handler[i].original_address == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149) * Send a "talk register 3" command to address i
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) * to provoke a collision if there is more than
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) * one device at this address.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 153) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 154) (i << 4) | 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 156) * Move the device(s) which didn't detect a
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 157) * collision to address `highFree'. Hopefully
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) * this only moves one device.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160) adb_request(&req, NULL, ADBREQ_SYNC, 3,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) (i<< 4) | 0xb, (highFree | 0x60), 0xfe);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 163) * See if anybody actually moved. This is suggested
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) * by HW TechNote 01:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) *
a7beab413e2e6 (Alexander A. Klimov 2020-07-17 20:35:22 +0200 166) * https://developer.apple.com/technotes/hw/hw_01.html
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 168) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) (highFree << 4) | 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170) if (req.reply_len <= 1) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 172) * Test whether there are any device(s) left
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 173) * at address i.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 174) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 175) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) (i << 4) | 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 177) if (req.reply_len > 1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) * There are still one or more devices
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 180) * left at address i. Register the one(s)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 181) * we moved to `highFree', and find a new
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 182) * value for highFree.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 183) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 184) adb_handler[highFree].original_address =
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 185) adb_handler[i].original_address;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186) while (highFree > 0 &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187) adb_handler[highFree].original_address)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188) highFree--;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189) if (highFree <= 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 192) noMovement = 0;
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 193) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 194) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 195) * No devices left at address i; move the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 196) * one(s) we moved to `highFree' back to i.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 197) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198) adb_request(&req, NULL, ADBREQ_SYNC, 3,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 199) (highFree << 4) | 0xb,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 200) (i | 0x60), 0xfe);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 202) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 203) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 205) /* Now fill in the handler_id field of the adb_handler entries. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 206) for (i = 1; i < 16; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 207) if (adb_handler[i].original_address == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 208) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 209) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 210) (i << 4) | 0xf);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 211) adb_handler[i].handler_id = req.reply[2];
2341629eadc4a (Finn Thain 2018-09-11 20:18:44 -0400 212) printk(KERN_DEBUG "adb device [%d]: %d 0x%X\n", i,
2341629eadc4a (Finn Thain 2018-09-11 20:18:44 -0400 213) adb_handler[i].original_address,
2341629eadc4a (Finn Thain 2018-09-11 20:18:44 -0400 214) adb_handler[i].handler_id);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 215) devmask |= 1 << i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 216) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 217) return devmask;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 218) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 219)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 220) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 221) * This kernel task handles ADB probing. It dies once probing is
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) * completed.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 224) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225) adb_probe_task(void *x)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 226) {
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 227) pr_debug("adb: starting probe task...\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 228) do_adb_reset_bus();
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 229) pr_debug("adb: finished probe task...\n");
1b6dd9baa728d (Oleg Nesterov 2007-07-15 23:41:29 -0700 230)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 231) up(&adb_probe_mutex);
1b6dd9baa728d (Oleg Nesterov 2007-07-15 23:41:29 -0700 232)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 233) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) static void
3e577a80ea85e (Al Viro 2006-12-06 18:41:45 +0000 237) __adb_probe_task(struct work_struct *bullshit)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 238) {
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 239) kthread_run(adb_probe_task, NULL, "kadbprobe");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 240) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 241)
3e577a80ea85e (Al Viro 2006-12-06 18:41:45 +0000 242) static DECLARE_WORK(adb_reset_work, __adb_probe_task);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 243)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 244) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) adb_reset_bus(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) if (__adb_probe_sync) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248) do_adb_reset_bus();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 249) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 250) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 251)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252) down(&adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 253) schedule_work(&adb_reset_work);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 254) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 255) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 257) #ifdef CONFIG_PM
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 258) /*
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 259) * notify clients before sleep
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 260) */
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 261) static int __adb_suspend(struct platform_device *dev, pm_message_t state)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 262) {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 263) adb_got_sleep = 1;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 264) /* We need to get a lock on the probe thread */
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 265) down(&adb_probe_mutex);
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 266) /* Stop autopoll */
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 267) if (adb_controller->autopoll)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 268) adb_controller->autopoll(0);
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 269) blocking_notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 270)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 271) return 0;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 272) }
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 273)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 274) static int adb_suspend(struct device *dev)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 275) {
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 276) return __adb_suspend(to_platform_device(dev), PMSG_SUSPEND);
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 277) }
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 278)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 279) static int adb_freeze(struct device *dev)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 280) {
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 281) return __adb_suspend(to_platform_device(dev), PMSG_FREEZE);
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 282) }
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 283)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 284) static int adb_poweroff(struct device *dev)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 285) {
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 286) return __adb_suspend(to_platform_device(dev), PMSG_HIBERNATE);
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 287) }
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 288)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 289) /*
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 290) * reset bus after sleep
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 291) */
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 292) static int __adb_resume(struct platform_device *dev)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 293) {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 294) adb_got_sleep = 0;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 295) up(&adb_probe_mutex);
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 296) adb_reset_bus();
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 297)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 298) return 0;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 299) }
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 300)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 301) static int adb_resume(struct device *dev)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 302) {
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 303) return __adb_resume(to_platform_device(dev));
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 304) }
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 305) #endif /* CONFIG_PM */
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 306)
9b4a8dd2e9f8a (Adrian Bunk 2008-06-24 03:46:57 +1000 307) static int __init adb_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 308) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 309) struct adb_driver *driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 310) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 311)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 312) #ifdef CONFIG_PPC32
e8222502ee615 (Benjamin Herrenschmidt 2006-03-28 23:15:54 +1100 313) if (!machine_is(chrp) && !machine_is(powermac))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 314) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 315) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 316) #ifdef CONFIG_MAC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 317) if (!MACH_IS_MAC)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 318) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 319) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 320)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 321) /* xmon may do early-init */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 322) if (adb_inited)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 323) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 324) adb_inited = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 325)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 326) adb_controller = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 327)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 328) i = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 329) while ((driver = adb_driver_list[i++]) != NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 330) if (!driver->probe()) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 331) adb_controller = driver;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 332) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 333) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 334) }
18814ee846357 (Finn Thain 2009-11-17 20:03:05 +1100 335) if (adb_controller != NULL && adb_controller->init &&
18814ee846357 (Finn Thain 2009-11-17 20:03:05 +1100 336) adb_controller->init())
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 337) adb_controller = NULL;
18814ee846357 (Finn Thain 2009-11-17 20:03:05 +1100 338) if (adb_controller == NULL) {
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 339) pr_warn("Warning: no ADB interface detected\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 340) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 341) #ifdef CONFIG_PPC
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 342) if (of_machine_is_compatible("AAPL,PowerBook1998") ||
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 343) of_machine_is_compatible("PowerBook1,1"))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 344) sleepy_trackpad = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 345) #endif /* CONFIG_PPC */
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 346)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 347) adbdev_init();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 348) adb_reset_bus();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 349) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 350) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 351) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 352)
faa5b9daa8bd8 (Robert P. J. Day 2008-05-15 09:12:53 +1000 353) device_initcall(adb_init);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 354)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 355) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 356) do_adb_reset_bus(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 357) {
70b52b3869a31 (Johannes Berg 2007-03-19 11:53:55 +0100 358) int ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 359)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 360) if (adb_controller == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 361) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 362)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 363) if (adb_controller->autopoll)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364) adb_controller->autopoll(0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365)
70b52b3869a31 (Johannes Berg 2007-03-19 11:53:55 +0100 366) blocking_notifier_call_chain(&adb_client_list,
70b52b3869a31 (Johannes Berg 2007-03-19 11:53:55 +0100 367) ADB_MSG_PRE_RESET, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 368)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369) if (sleepy_trackpad) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370) /* Let the trackpad settle down */
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 371) msleep(500);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 373)
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 374) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 375) write_lock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 376) memset(adb_handler, 0, sizeof(adb_handler));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 377) write_unlock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 378)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 379) /* That one is still a bit synchronous, oh well... */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 380) if (adb_controller->reset_bus)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 381) ret = adb_controller->reset_bus();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 382) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 383) ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 384)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 385) if (sleepy_trackpad) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 386) /* Let the trackpad settle down */
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 387) msleep(1500);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 388) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 389)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 390) if (!ret) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 391) autopoll_devs = adb_scan_bus();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 392) if (adb_controller->autopoll)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 393) adb_controller->autopoll(autopoll_devs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 394) }
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 395) mutex_unlock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 396)
70b52b3869a31 (Johannes Berg 2007-03-19 11:53:55 +0100 397) blocking_notifier_call_chain(&adb_client_list,
70b52b3869a31 (Johannes Berg 2007-03-19 11:53:55 +0100 398) ADB_MSG_POST_RESET, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 399)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 400) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 401) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 402)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 403) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 404) adb_poll(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 405) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 406) if ((adb_controller == NULL)||(adb_controller->poll == NULL))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 407) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 408) adb_controller->poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 409) }
370a3abdbba85 (Anton Blanchard 2014-08-20 08:00:00 +1000 410) EXPORT_SYMBOL(adb_poll);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 411)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 412) static void adb_sync_req_done(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 413) {
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 414) struct completion *comp = req->arg;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 415)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 416) complete(comp);
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 417) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 418)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 419) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 420) adb_request(struct adb_request *req, void (*done)(struct adb_request *),
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 421) int flags, int nbytes, ...)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 422) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 423) va_list list;
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 424) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 425) int rc;
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 426) struct completion comp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 427)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 428) if ((adb_controller == NULL) || (adb_controller->send_request == NULL))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 429) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 430) if (nbytes < 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 431) return -EINVAL;
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 432)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 433) req->nbytes = nbytes+1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 434) req->done = done;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 435) req->reply_expected = flags & ADBREQ_REPLY;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 436) req->data[0] = ADB_PACKET;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 437) va_start(list, nbytes);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 438) for (i = 0; i < nbytes; ++i)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 439) req->data[i+1] = va_arg(list, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 440) va_end(list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 441)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 442) if (flags & ADBREQ_NOSEND)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 443) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 444)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 445) /* Synchronous requests block using an on-stack completion */
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 446) if (flags & ADBREQ_SYNC) {
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 447) WARN_ON(done);
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 448) req->done = adb_sync_req_done;
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 449) req->arg = ∁
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 450) init_completion(&comp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 451) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 452)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 453) rc = adb_controller->send_request(req, 0);
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 454)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 455) if ((flags & ADBREQ_SYNC) && !rc && !req->complete)
c61dace9a10a4 (Paul Mackerras 2007-12-13 15:11:22 +1100 456) wait_for_completion(&comp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 457)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 458) return rc;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 459) }
370a3abdbba85 (Anton Blanchard 2014-08-20 08:00:00 +1000 460) EXPORT_SYMBOL(adb_request);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 461)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 462) /* Ultimately this should return the number of devices with
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 463) the given default id.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 464) And it does it now ! Note: changed behaviour: This function
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 465) will now register if default_id _and_ handler_id both match
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 466) but handler_id can be left to 0 to match with default_id only.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 467) When handler_id is set, this function will try to adjust
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 468) the handler_id id it doesn't match. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 469) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 470) adb_register(int default_id, int handler_id, struct adb_ids *ids,
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 471) void (*handler)(unsigned char *, int, int))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 472) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 473) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 474)
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 475) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 476) ids->nids = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 477) for (i = 1; i < 16; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 478) if ((adb_handler[i].original_address == default_id) &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 479) (!handler_id || (handler_id == adb_handler[i].handler_id) ||
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 480) try_handler_change(i, handler_id))) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 481) if (adb_handler[i].handler != 0) {
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 482) pr_err("Two handlers for ADB device %d\n",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 483) default_id);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 484) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 485) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 486) write_lock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 487) adb_handler[i].handler = handler;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 488) write_unlock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 489) ids->id[ids->nids++] = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 490) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 491) }
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 492) mutex_unlock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 493) return ids->nids;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 494) }
370a3abdbba85 (Anton Blanchard 2014-08-20 08:00:00 +1000 495) EXPORT_SYMBOL(adb_register);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 496)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 497) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 498) adb_unregister(int index)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 499) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 500) int ret = -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 501)
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 502) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 503) write_lock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 504) if (adb_handler[index].handler) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 505) while(adb_handler[index].busy) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 506) write_unlock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 507) yield();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 508) write_lock_irq(&adb_handler_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 509) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 510) ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 511) adb_handler[index].handler = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 512) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 513) write_unlock_irq(&adb_handler_lock);
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 514) mutex_unlock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 515) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 516) }
370a3abdbba85 (Anton Blanchard 2014-08-20 08:00:00 +1000 517) EXPORT_SYMBOL(adb_unregister);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 518)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 519) void
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 520) adb_input(unsigned char *buf, int nb, int autopoll)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 521) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 522) int i, id;
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 523) static int dump_adb_input;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 524) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 525)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 526) void (*handler)(unsigned char *, int, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 527)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 528) /* We skip keystrokes and mouse moves when the sleep process
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 529) * has been started. We stop autopoll, but this is another security
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 530) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 531) if (adb_got_sleep)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 532) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 533)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 534) id = buf[0] >> 4;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 535) if (dump_adb_input) {
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 536) pr_info("adb packet: ");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 537) for (i = 0; i < nb; ++i)
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 538) pr_cont(" %x", buf[i]);
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 539) pr_cont(", id = %d\n", id);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 540) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 541) write_lock_irqsave(&adb_handler_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 542) handler = adb_handler[id].handler;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 543) if (handler != NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 544) adb_handler[id].busy = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 545) write_unlock_irqrestore(&adb_handler_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 546) if (handler != NULL) {
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 547) (*handler)(buf, nb, autopoll);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 548) wmb();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 549) adb_handler[id].busy = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 550) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 551)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 552) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 553)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 554) /* Try to change handler to new_id. Will return 1 if successful. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 555) static int try_handler_change(int address, int new_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 556) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 557) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 558)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 559) if (adb_handler[address].handler_id == new_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 560) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 561) adb_request(&req, NULL, ADBREQ_SYNC, 3,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 562) ADB_WRITEREG(address, 3), address | 0x20, new_id);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 563) adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 564) ADB_READREG(address, 3));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 565) if (req.reply_len < 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 566) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 567) if (req.reply[2] != new_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 568) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 569) adb_handler[address].handler_id = req.reply[2];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 570)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 571) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 572) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 573)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 574) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 575) adb_try_handler_change(int address, int new_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 576) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 577) int ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 578)
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 579) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 580) ret = try_handler_change(address, new_id);
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 581) mutex_unlock(&adb_handler_mutex);
2341629eadc4a (Finn Thain 2018-09-11 20:18:44 -0400 582) if (ret)
2341629eadc4a (Finn Thain 2018-09-11 20:18:44 -0400 583) pr_debug("adb handler change: [%d] 0x%X\n", address, new_id);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 584) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 585) }
370a3abdbba85 (Anton Blanchard 2014-08-20 08:00:00 +1000 586) EXPORT_SYMBOL(adb_try_handler_change);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 587)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 588) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 589) adb_get_infos(int address, int *original_address, int *handler_id)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 590) {
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 591) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 592) *original_address = adb_handler[address].original_address;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 593) *handler_id = adb_handler[address].handler_id;
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 594) mutex_unlock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 595)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 596) return (*original_address != 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 597) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 598)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 599)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 600) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 601) * /dev/adb device driver.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 602) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 603)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 604) #define ADB_MAJOR 56 /* major number for /dev/adb */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 605)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 606) struct adbdev_state {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 607) spinlock_t lock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 608) atomic_t n_pending;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 609) struct adb_request *completed;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 610) wait_queue_head_t wait_queue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 611) int inuse;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 612) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 613)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 614) static void adb_write_done(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 615) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 616) struct adbdev_state *state = (struct adbdev_state *) req->arg;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 617) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 618)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 619) if (!req->complete) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 620) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 621) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 622) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 623) spin_lock_irqsave(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 624) atomic_dec(&state->n_pending);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 625) if (!state->inuse) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 626) kfree(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 627) if (atomic_read(&state->n_pending) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 628) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 629) kfree(state);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 630) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 631) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 632) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 633) struct adb_request **ap = &state->completed;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 634) while (*ap != NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 635) ap = &(*ap)->next;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 636) req->next = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 637) *ap = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 638) wake_up_interruptible(&state->wait_queue);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 639) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 640) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 641) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 642)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 643) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 644) do_adb_query(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 645) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 646) int ret = -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 647)
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 648) switch(req->data[1]) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 649) case ADB_QUERY_GETDEVINFO:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 650) if (req->nbytes < 3)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 651) break;
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 652) mutex_lock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 653) req->reply[0] = adb_handler[req->data[2]].original_address;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 654) req->reply[1] = adb_handler[req->data[2]].handler_id;
af3ce514ade2f (Daniel Walker 2008-05-03 06:34:03 +1000 655) mutex_unlock(&adb_handler_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 656) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 657) req->reply_len = 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 658) adb_write_done(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 659) ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 660) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 661) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 662) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 663) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 664)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 665) static int adb_open(struct inode *inode, struct file *file)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 666) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 667) struct adbdev_state *state;
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 668) int ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 669)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 670) mutex_lock(&adb_mutex);
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 671) if (iminor(inode) > 0 || adb_controller == NULL) {
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 672) ret = -ENXIO;
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 673) goto out;
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 674) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 675) state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 676) if (state == 0) {
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 677) ret = -ENOMEM;
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 678) goto out;
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 679) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 680) file->private_data = state;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 681) spin_lock_init(&state->lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 682) atomic_set(&state->n_pending, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 683) state->completed = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 684) init_waitqueue_head(&state->wait_queue);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 685) state->inuse = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 686)
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 687) out:
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 688) mutex_unlock(&adb_mutex);
26ce4f0684ef4 (Jonathan Corbet 2008-05-16 14:19:56 -0600 689) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 690) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 691)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 692) static int adb_release(struct inode *inode, struct file *file)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 693) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 694) struct adbdev_state *state = file->private_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 695) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 696)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 697) mutex_lock(&adb_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 698) if (state) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 699) file->private_data = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 700) spin_lock_irqsave(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 701) if (atomic_read(&state->n_pending) == 0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 702) && state->completed == NULL) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 703) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 704) kfree(state);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 705) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 706) state->inuse = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 707) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 708) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 709) }
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 710) mutex_unlock(&adb_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 711) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 712) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 713)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 714) static ssize_t adb_read(struct file *file, char __user *buf,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 715) size_t count, loff_t *ppos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 716) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 717) int ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 718) struct adbdev_state *state = file->private_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 719) struct adb_request *req;
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 720) DECLARE_WAITQUEUE(wait, current);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 721) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 722)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 723) if (count < 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 724) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 725) if (count > sizeof(req->reply))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 726) count = sizeof(req->reply);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 727)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 728) req = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 729) spin_lock_irqsave(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 730) add_wait_queue(&state->wait_queue, &wait);
64f8c13561fbd (majianpeng 2012-02-03 14:35:59 +0000 731) set_current_state(TASK_INTERRUPTIBLE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 732)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 733) for (;;) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 734) req = state->completed;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 735) if (req != NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 736) state->completed = req->next;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 737) else if (atomic_read(&state->n_pending) == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 738) ret = -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 739) if (req != NULL || ret != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 740) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 741)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 742) if (file->f_flags & O_NONBLOCK) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 743) ret = -EAGAIN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 744) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 745) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 746) if (signal_pending(current)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 747) ret = -ERESTARTSYS;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 748) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 749) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 750) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 751) schedule();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 752) spin_lock_irqsave(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 753) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 754)
64f8c13561fbd (majianpeng 2012-02-03 14:35:59 +0000 755) set_current_state(TASK_RUNNING);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 756) remove_wait_queue(&state->wait_queue, &wait);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 757) spin_unlock_irqrestore(&state->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 758)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 759) if (ret)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 760) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 761)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 762) ret = req->reply_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 763) if (ret > count)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 764) ret = count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 765) if (ret > 0 && copy_to_user(buf, req->reply, ret))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 766) ret = -EFAULT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 767)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 768) kfree(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 769) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 770) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 771)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 772) static ssize_t adb_write(struct file *file, const char __user *buf,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 773) size_t count, loff_t *ppos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 774) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 775) int ret/*, i*/;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 776) struct adbdev_state *state = file->private_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 777) struct adb_request *req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 778)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 779) if (count < 2 || count > sizeof(req->data))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 780) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 781) if (adb_controller == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 782) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 783)
5cbded585d129 (Robert P. J. Day 2006-12-13 00:35:56 -0800 784) req = kmalloc(sizeof(struct adb_request),
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 785) GFP_KERNEL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 786) if (req == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 787) return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 788)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 789) req->nbytes = count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 790) req->done = adb_write_done;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 791) req->arg = (void *) state;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 792) req->complete = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 793)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 794) ret = -EFAULT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 795) if (copy_from_user(req->data, buf, count))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 796) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 797)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 798) atomic_inc(&state->n_pending);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 799)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 800) /* If a probe is in progress or we are sleeping, wait for it to complete */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 801) down(&adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 802)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 803) /* Queries are special requests sent to the ADB driver itself */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 804) if (req->data[0] == ADB_QUERY) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 805) if (count > 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 806) ret = do_adb_query(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 807) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 808) ret = -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 809) up(&adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 810) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 811) /* Special case for ADB_BUSRESET request, all others are sent to
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 812) the controller */
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 813) else if ((req->data[0] == ADB_PACKET) && (count > 1)
74e7cd432c3d1 (Brandon Stewart 2014-01-27 19:43:17 -0600 814) && (req->data[1] == ADB_BUSRESET)) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 815) ret = do_adb_reset_bus();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 816) up(&adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 817) atomic_dec(&state->n_pending);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 818) if (ret == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 819) ret = count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 820) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 821) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 822) req->reply_expected = ((req->data[1] & 0xc) == 0xc);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 823) if (adb_controller && adb_controller->send_request)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 824) ret = adb_controller->send_request(req, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 825) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 826) ret = -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 827) up(&adb_probe_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 828) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 829)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 830) if (ret != 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 831) atomic_dec(&state->n_pending);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 832) goto out;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 833) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 834) return count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 835)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 836) out:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 837) kfree(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 838) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 839) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 840)
fa027c2a0a0d6 (Arjan van de Ven 2007-02-12 00:55:33 -0800 841) static const struct file_operations adb_fops = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 842) .owner = THIS_MODULE,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 843) .llseek = no_llseek,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 844) .read = adb_read,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 845) .write = adb_write,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 846) .open = adb_open,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 847) .release = adb_release,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 848) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 849)
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 850) #ifdef CONFIG_PM
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 851) static const struct dev_pm_ops adb_dev_pm_ops = {
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 852) .suspend = adb_suspend,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 853) .resume = adb_resume,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 854) /* Hibernate hooks */
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 855) .freeze = adb_freeze,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 856) .thaw = adb_resume,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 857) .poweroff = adb_poweroff,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 858) .restore = adb_resume,
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 859) };
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 860) #endif
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 861)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 862) static struct platform_driver adb_pfdrv = {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 863) .driver = {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 864) .name = "adb",
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 865) #ifdef CONFIG_PM
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 866) .pm = &adb_dev_pm_ops,
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 867) #endif
639291f263c14 (Shuah Khan 2014-02-10 09:12:27 -0700 868) },
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 869) };
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 870)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 871) static struct platform_device adb_pfdev = {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 872) .name = "adb",
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 873) };
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 874)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 875) static int __init
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 876) adb_dummy_probe(struct platform_device *dev)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 877) {
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 878) if (dev == &adb_pfdev)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 879) return 0;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 880) return -ENODEV;
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 881) }
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 882)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 883) static void __init
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 884) adbdev_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 885) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 886) if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) {
f2be6295684b0 (Andreas Schwab 2016-11-28 21:29:07 +0100 887) pr_err("adb: unable to get major %d\n", ADB_MAJOR);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 888) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 889) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 890)
56b2293595b2e (Greg Kroah-Hartman 2005-03-23 10:01:41 -0800 891) adb_dev_class = class_create(THIS_MODULE, "adb");
56b2293595b2e (Greg Kroah-Hartman 2005-03-23 10:01:41 -0800 892) if (IS_ERR(adb_dev_class))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 893) return;
a9b12619f7b6f (Greg Kroah-Hartman 2008-07-21 20:03:34 -0700 894) device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb");
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 895)
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 896) platform_device_register(&adb_pfdev);
c9f6d3d5c6d4f (Johannes Berg 2007-12-12 01:21:25 +1100 897) platform_driver_probe(&adb_pfdrv, adb_dummy_probe);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 898) }