3 * Open Hack'Ware BIOS ADB bus support, ported to OpenBIOS
5 * Copyright (c) 2005 Jocelyn Mayer
6 * Copyright (c) 2005 Stefan Reinauer
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
23 #include "libopenbios/bindings.h"
24 #include "libc/vsprintf.h"
28 #include "adb_mouse.h"
30 DECLARE_UNNAMED_NODE( adb
, INSTALL_OPEN
, sizeof(int));
33 adb_initialize (int *idx
)
35 phandle_t ph
=get_cur_dev();
40 set_property(ph
, "compatible", "adb", 4);
41 set_int_property(ph
, "#address-cells", 1);
42 set_int_property(ph
, "#size-cells", 0);
56 NODE_METHODS( adb
) = {
57 { NULL
, adb_initialize
},
59 { "close", adb_close
},
62 adb_bus_t
*adb_bus_new (void *host
,
63 int (*req
)(void *host
, const uint8_t *snd_buf
,
64 int len
, uint8_t *rcv_buf
))
68 new = malloc(sizeof(adb_bus_t
));
77 /* Check and relocate all ADB devices as suggested in
78 * ADB_manager Apple documentation
81 int adb_bus_init (char *path
, adb_bus_t
*bus
)
84 uint8_t buffer
[ADB_BUF_SIZE
];
85 uint8_t adb_addresses
[16] =
86 { 8, 9, 10, 11, 12, 13, 14, -1, -1, -1, -1, -1, -1, -1, 0, };
87 adb_dev_t tmp_device
, **cur
;
89 int reloc
= 0, next_free
= 7;
92 snprintf(buf
, sizeof(buf
), "%s/adb", path
);
93 REGISTER_NAMED_NODE( adb
, buf
);
98 memset(&tmp_device
, 0, sizeof(adb_dev_t
));
100 for (address
= 1; address
< 8 && adb_addresses
[reloc
] > 0;) {
101 if (address
== ADB_RES
) {
106 //ADB_DPRINTF("Check device on ADB address %d\n", address);
107 tmp_device
.addr
= address
;
108 switch (adb_reg_get(&tmp_device
, 3, buffer
)) {
110 //ADB_DPRINTF("No device on ADB address %d\n", address);
111 /* Register this address as free */
112 if (adb_addresses
[next_free
] != 0)
113 adb_addresses
[next_free
++] = address
;
114 /* Check next ADB address */
118 /* One device answered :
119 * make it available and relocate it to a free address
121 if (buffer
[0] == ADB_CHADDR
) {
122 /* device self test failed */
123 ADB_DPRINTF("device on ADB address %d self-test failed "
124 "%02x %02x %02x\n", address
,
125 buffer
[0], buffer
[1], buffer
[2]);
128 //ADB_DPRINTF("device on ADB address %d self-test OK\n",
132 ADB_DPRINTF("Relocate device on ADB address %d to %d (%d)\n",
133 address
, adb_addresses
[reloc
], reloc
);
134 buffer
[0] = ((buffer
[0] & 0x40) & ~0x90) | adb_addresses
[reloc
];
137 buffer
[1] = ADB_CHADDR_NOCOLL
;
138 if (adb_reg_set(&tmp_device
, 3, buffer
, 2) < 0) {
139 ADB_DPRINTF("ADB device relocation failed\n");
143 *cur
= malloc(sizeof(adb_dev_t
));
147 (*cur
)->type
= address
;
149 (*cur
)->addr
= adb_addresses
[reloc
++];
152 switch ((*cur
)->type
) {
154 ADB_DPRINTF("Found one protected device\n");
157 ADB_DPRINTF("Found one keyboard on address %d\n", address
);
158 adb_kbd_new(buf
, *cur
);
161 ADB_DPRINTF("Found one mouse on address %d\n", address
);
162 adb_mouse_new(buf
, *cur
);
165 ADB_DPRINTF("Found one absolute positioning device\n");
168 ADB_DPRINTF("Found one modem\n");
171 ADB_DPRINTF("Found one ADB res device\n");
174 ADB_DPRINTF("Found one ADB misc device\n");
177 cur
= &((*cur
)->next
);
182 /* SHOULD NOT HAPPEN : register 3 is always two bytes long */
183 ADB_DPRINTF("Invalid returned len for ADB register 3\n");
187 ADB_DPRINTF("error gettting ADB register 3\n");
195 int adb_cmd (adb_dev_t
*dev
, uint8_t cmd
, uint8_t reg
,
196 uint8_t *buf
, int len
)
198 uint8_t adb_send
[ADB_BUF_SIZE
], adb_rcv
[ADB_BUF_SIZE
];
200 //ADB_DPRINTF("cmd: %d reg: %d len: %d\n", cmd, reg, len);
201 if (dev
->bus
== NULL
|| dev
->bus
->req
== NULL
) {
202 ADB_DPRINTF("ERROR: invalid bus !\n");
206 if (cmd
!= ADB_LISTEN
&& len
!= 0) {
207 /* No buffer transmitted but for LISTEN command */
208 ADB_DPRINTF("in buffer for cmd %d\n", cmd
);
211 if (cmd
== ADB_LISTEN
&& ((len
< 2 || len
> 8) || buf
== NULL
)) {
212 /* Need a buffer with a regular register size for LISTEN command */
213 ADB_DPRINTF("no/invalid buffer for ADB_LISTEN (%d)\n", len
);
216 if ((cmd
== ADB_TALK
|| cmd
== ADB_LISTEN
) && reg
> 3) {
217 /* Need a valid register number for LISTEN and TALK commands */
218 ADB_DPRINTF("invalid reg for TALK/LISTEN command (%d %d)\n", cmd
, reg
);
223 adb_send
[0] = ADB_SEND_RESET
;
226 adb_send
[0] = (dev
->addr
<< 4) | ADB_FLUSH
;
229 memcpy(adb_send
+ 1, buf
, len
);
232 adb_send
[0] = (dev
->addr
<< 4) | cmd
| reg
;
235 memset(adb_rcv
, 0, ADB_BUF_SIZE
);
236 len
= (*dev
->bus
->req
)(dev
->bus
->host
, adb_send
, len
+ 1, adb_rcv
);
238 //printk("%x %x %x %x\n", adb_rcv[0], adb_rcv[1], adb_rcv[2], adb_rcv[3]);
245 /* Register transmitted */
247 memcpy(buf
, adb_rcv
, len
);
250 /* Should never happen */
251 //ADB_DPRINTF("Cmd %d returned %d bytes !\n", cmd, len);
254 //ADB_DPRINTF("retlen: %d\n", len);