|
|
1.1 root 1: /*
2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: #include <IOKit/assert.h>
24: #include <IOKit/IOLib.h>
25: #include "ApplePS2Mouse.h"
26:
27: // =============================================================================
28: // ApplePS2Mouse Class Implementation
29: //
30:
31: #define super IOHIPointing
32: OSDefineMetaClassAndStructors(ApplePS2Mouse, IOHIPointing);
33:
34: UInt32 ApplePS2Mouse::deviceType() { return NX_EVS_DEVICE_TYPE_MOUSE; };
35: UInt32 ApplePS2Mouse::interfaceID() { return NX_EVS_DEVICE_INTERFACE_BUS_ACE; };
36:
37: IOItemCount ApplePS2Mouse::buttonCount() { return 3; };
38: IOFixed ApplePS2Mouse::resolution() { return _resolution; };
39:
40: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
41:
42: bool ApplePS2Mouse::init(OSDictionary * properties)
43: {
44: //
45: // Initialize this object's minimal state. This is invoked right after this
46: // object is instantiated.
47: //
48:
49: if (!super::init(properties)) return false;
50:
51: _device = 0;
52: _interruptHandlerInstalled = false;
53: _packetByteCount = 0;
54: _packetLength = kPacketLengthStandard;
55: _resolution = (150) << 16; // (default is 150 dpi; 6 counts/mm)
56: _type = kMouseTypeStandard;
57:
58: return true;
59: }
60:
61: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62:
63: ApplePS2Mouse * ApplePS2Mouse::probe(IOService * provider, SInt32 * score)
64: {
65: //
66: // The driver has been instructed to verify the presence of the actual
67: // hardware we represent. We are guaranteed by the controller that the
68: // mouse clock is enabled and the mouse itself is disabled (thus it
69: // won't send any asynchronous mouse data that may mess up the
70: // responses expected by the commands we send it).
71: //
72:
73: ApplePS2MouseDevice * device = (ApplePS2MouseDevice *)provider;
74: PS2Request * request = device->allocateRequest();
75: bool success;
76:
77: if (!super::probe(provider, score)) return 0;
78:
79: //
80: // Check to see if acknowledges are being received for commands to the mouse.
81: //
82:
83: // (get information command)
84: request->commands[0].command = kPS2C_WriteCommandPort;
85: request->commands[0].inOrOut = kCP_TransmitToMouse;
86: request->commands[1].command = kPS2C_WriteDataPort;
87: request->commands[1].inOrOut = kDP_GetMouseInformation;
88: request->commands[2].command = kPS2C_ReadDataPortAndCompare;
89: request->commands[2].inOrOut = kSC_Acknowledge;
90: request->commands[3].command = kPS2C_ReadDataPort;
91: request->commands[3].inOrOut = 0;
92: request->commands[4].command = kPS2C_ReadDataPort;
93: request->commands[4].inOrOut = 0;
94: request->commands[5].command = kPS2C_ReadDataPort;
95: request->commands[5].inOrOut = 0;
96: request->commandsCount = 6;
97: device->submitRequestAndBlock(request);
98:
99: // (free the request)
100: success = (request->commandsCount == 6);
101: device->freeRequest(request);
102:
103: return (success) ? this : 0;
104: }
105:
106: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
107:
108: bool ApplePS2Mouse::start(IOService * provider)
109: {
110: //
111: // The driver has been instructed to start. This is called after a
112: // successful probe and match.
113: //
114:
115: if (!super::start(provider)) return false;
116:
117: //
118: // Maintain a pointer to and retain the provider object.
119: //
120:
121: _device = (ApplePS2MouseDevice *)provider;
122: _device->retain();
123:
124: //
125: // Install our driver's interrupt handler, for asynchronous data delivery.
126: //
127:
128: _device->installInterruptAction(this,
129: (PS2InterruptAction)&ApplePS2Mouse::interruptOccurred);
130: _interruptHandlerInstalled = true;
131:
132: //
133: // Obtain our mouse's resolution and sampling rate.
134: //
135:
136: switch (getMouseInformation() & 0x00FF00)
137: {
138: case 0x0000: _resolution = (25) << 16; break; // 25 dpi
139: case 0x0100: _resolution = (50) << 16; break; // 50 dpi
140: case 0x0200: _resolution = (100) << 16; break; // 100 dpi
141: case 0x0300: _resolution = (200) << 16; break; // 200 dpi
142: default: _resolution = (150) << 16; break; // 150 dpi
143: }
144:
145: //
146: // Enable the Intellimouse mode, should this be an Intellimouse.
147: //
148:
149: if ( setIntellimouseMode() == true )
150: {
151: _packetLength = kPacketLengthIntellimouse;
152: _type = kMouseTypeIntellimouse;
153: }
154:
155: //
156: // Enable the mouse clock (should already be so) and the mouse IRQ line.
157: //
158:
159: setCommandByte(kCB_EnableMouseIRQ, kCB_DisableMouseClock);
160:
161: //
162: // Finally, we enable the mouse itself, so that it may start reporting
163: // mouse events.
164: //
165:
166: setMouseEnable(true);
167:
168: return true;
169: }
170:
171: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172:
173: void ApplePS2Mouse::stop(IOService * provider)
174: {
175: //
176: // The driver has been instructed to stop. Note that we must break all
177: // connections to other service objects now (ie. no registered actions,
178: // no pointers and retains to objects, etc), if any.
179: //
180:
181: assert(_device == provider);
182:
183: //
184: // Disable the mouse itself, so that it may stop reporting mouse events.
185: //
186:
187: setMouseEnable(false);
188:
189: //
190: // Disable the mouse clock and the mouse IRQ line.
191: //
192:
193: setCommandByte(kCB_DisableMouseClock, kCB_EnableMouseIRQ);
194:
195: //
196: // Uninstall the interrupt handler.
197: //
198:
199: if ( _interruptHandlerInstalled ) _device->uninstallInterruptAction();
200: _interruptHandlerInstalled = false;
201:
202: //
203: // Release the pointer to the provider object.
204: //
205:
206: _device->release();
207: _device = 0;
208:
209: super::stop(provider);
210: }
211:
212: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
213:
214: void ApplePS2Mouse::interruptOccurred(UInt8 data) // PS2InterruptAction
215: {
216: //
217: // This will be invoked automatically from our device when asynchronous mouse
218: // needs to be delivered. Process the mouse data. Do NOT send any BLOCKING
219: // commands to our device in this context.
220: //
221: // We ignore all bytes until we see the start of a packet, otherwise the mouse
222: // packets may get out of sequence and things will get very confusing.
223: //
224:
225: if (_packetByteCount == 0 && ((data == kSC_Acknowledge) || !(data & 0x08)))
226: {
227: IOLog("%s: Unexpected data from PS/2 controller.\n", getName());
228: return;
229: }
230:
231: //
232: // Add this byte to the packet buffer. If the packet is complete, that is,
233: // we have the three bytes, dispatch this packet for processing.
234: //
235:
236: _packetBuffer[_packetByteCount++] = data;
237:
238: if (_packetByteCount == _packetLength)
239: {
240: dispatchRelativePointerEventWithPacket(_packetBuffer);
241: _packetByteCount = 0;
242: }
243: }
244:
245: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246:
247: void ApplePS2Mouse::dispatchRelativePointerEventWithPacket(UInt8 * packet)
248: {
249: //
250: // Process the three byte mouse packet that was retreived from the mouse.
251: // The format of the bytes is as follows:
252: //
253: // 7 6 5 4 3 2 1 0
254: // YO XO YS XS 1 M R L
255: // X7 X6 X5 X4 X3 X3 X1 X0
256: // Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
257: // Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 <- fourth byte returned only for Intellimouse type
258: //
259:
260: UInt32 buttons = 0;
261: SInt32 dx;
262: SInt32 dy;
263: SInt32 dz;
264: AbsoluteTime now;
265:
266: if ( !(packet[0] & 0x1) ) buttons |= 0x1; // left button (bit 0 in packet)
267: if ( !(packet[0] & 0x2) ) buttons |= 0x2; // right button (bit 1 in packet)
268: if ( !(packet[0] & 0x4) ) buttons |= 0x4; // middle button (bit 2 in packet)
269:
270: dx = ((packet[0] & 0x10) ? 0xffffff00 : 0 ) | packet[1];
271: dy = -(((packet[0] & 0x20) ? 0xffffff00 : 0 ) | packet[2]);
272: dz = (SInt32)((SInt8)packet[3]);
273:
274: clock_get_uptime(&now);
275:
276: dispatchRelativePointerEvent(dx, dy, buttons, now);
277:
278: return;
279: }
280:
281: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
282:
283: void ApplePS2Mouse::setMouseEnable(bool enable)
284: {
285: //
286: // Instructs the mouse to start or stop the reporting of mouse events.
287: // Be aware that while the mouse is enabled, asynchronous mouse events
288: // may arrive in the middle of command sequences sent to the controller,
289: // and may get confused for expected command responses.
290: //
291: // It is safe to issue this request from the interrupt/completion context.
292: //
293:
294: PS2Request * request = _device->allocateRequest();
295:
296: // (mouse enable/disable command)
297: request->commands[0].command = kPS2C_WriteCommandPort;
298: request->commands[0].inOrOut = kCP_TransmitToMouse;
299: request->commands[1].command = kPS2C_WriteDataPort;
300: request->commands[1].inOrOut = (enable)?kDP_Enable:kDP_SetDefaultsAndDisable;
301: request->commands[2].command = kPS2C_ReadDataPortAndCompare;
302: request->commands[2].inOrOut = kSC_Acknowledge;
303: request->commandsCount = 3;
304: _device->submitRequest(request); // asynchronous, auto-free'd
305: }
306:
307: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
308:
309: void ApplePS2Mouse::setMouseSampleRate(UInt8 sampleRate)
310: {
311: //
312: // Instructs the mouse to change its sampling rate to the given value, in
313: // reports per second.
314: //
315: // It is safe to issue this request from the interrupt/completion context.
316: //
317:
318: PS2Request * request = _device->allocateRequest();
319:
320: // (set mouse sample rate command)
321: request->commands[0].command = kPS2C_WriteCommandPort;
322: request->commands[0].inOrOut = kCP_TransmitToMouse;
323: request->commands[1].command = kPS2C_WriteDataPort;
324: request->commands[1].inOrOut = kDP_SetMouseSampleRate;
325: request->commands[2].command = kPS2C_ReadDataPortAndCompare;
326: request->commands[2].inOrOut = kSC_Acknowledge;
327: request->commands[3].command = kPS2C_WriteCommandPort;
328: request->commands[3].inOrOut = kCP_TransmitToMouse;
329: request->commands[4].command = kPS2C_WriteDataPort;
330: request->commands[4].inOrOut = sampleRate;
331: request->commands[5].command = kPS2C_ReadDataPortAndCompare;
332: request->commands[5].inOrOut = kSC_Acknowledge;
333: request->commandsCount = 6;
334: _device->submitRequest(request); // asynchronous, auto-free'd
335: }
336:
337: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
338:
339: bool ApplePS2Mouse::setIntellimouseMode()
340: {
341: //
342: // Determines whether this mouse is a Microsoft Intellimouse, and if it is,
343: // it enables it (the mouse will send 4 byte packets for mouse events from
344: // then on). Returns true if the Intellimouse mode was succesfully enabled.
345: //
346: // Do NOT issue this request from the interrupt/completion context.
347: //
348:
349: UInt32 mouseInfo;
350: bool isIntellimouse;
351:
352: //
353: // Obtain the current sample rate, in order that we may restore it after
354: // the Intellimouse command sequence completes.
355: //
356:
357: mouseInfo = getMouseInformation();
358:
359: if (mouseInfo == (UInt32)(-1)) return false;
360:
361: //
362: // Generate the special command sequence to enable the 'Intellimouse' mode.
363: // The sequence is to set the sampling rate to 200, 100, then 80, at which
364: // point the mouse will start sending 4 byte packets for mouse events and
365: // return a mouse ID of 3.
366: //
367:
368: setMouseSampleRate(200);
369: setMouseSampleRate(100);
370: setMouseSampleRate(80 );
371:
372: //
373: // Determine whether we have an Intellimouse by asking for the mouse's ID.
374: //
375:
376: isIntellimouse = ( getMouseID() == kMouseTypeIntellimouse );
377:
378: //
379: // Restore the original sampling rate, before we obliterated it.
380: //
381:
382: setMouseSampleRate(mouseInfo & 0x0000FF);
383:
384: return isIntellimouse;
385: }
386:
387: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
388:
389: UInt32 ApplePS2Mouse::getMouseInformation()
390: {
391: //
392: // Asks the mouse to transmit its three information bytes. Should the
393: // mouse not respond, a value of (UInt32)(-1) is returned.
394: //
395: // Do NOT issue this request from the interrupt/completion context.
396: //
397:
398: PS2Request * request = _device->allocateRequest();
399: UInt32 returnValue = (UInt32)(-1);
400:
401: // (get information command)
402: request->commands[0].command = kPS2C_WriteCommandPort;
403: request->commands[0].inOrOut = kCP_TransmitToMouse;
404: request->commands[1].command = kPS2C_WriteDataPort;
405: request->commands[1].inOrOut = kDP_GetMouseInformation;
406: request->commands[2].command = kPS2C_ReadDataPortAndCompare;
407: request->commands[2].inOrOut = kSC_Acknowledge;
408: request->commands[3].command = kPS2C_ReadDataPort;
409: request->commands[3].inOrOut = 0;
410: request->commands[4].command = kPS2C_ReadDataPort;
411: request->commands[4].inOrOut = 0;
412: request->commands[5].command = kPS2C_ReadDataPort;
413: request->commands[5].inOrOut = 0;
414: request->commandsCount = 6;
415: _device->submitRequestAndBlock(request);
416:
417: if (request->commandsCount == 6) // success?
418: {
419: returnValue = ((UInt32)request->commands[3].inOrOut << 16) |
420: ((UInt32)request->commands[4].inOrOut << 8 ) |
421: ((UInt32)request->commands[5].inOrOut);
422: }
423: _device->freeRequest(request);
424:
425: return returnValue;
426: }
427:
428: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
429:
430: UInt8 ApplePS2Mouse::getMouseID()
431: {
432: //
433: // Asks the mouse to transmit its identification byte. Should the mouse
434: // not respond, a value of (UInt8)(-1) is returned.
435: //
436: // Note that some documentation on PS/2 mice implies that two identification
437: // bytes are returned and not one. This was proven to be false in my tests.
438: //
439: // Do NOT issue this request from the interrupt/completion context.
440: //
441:
442: PS2Request * request = _device->allocateRequest();
443: UInt8 returnValue = (UInt8)(-1);
444:
445: // (get information command)
446: request->commands[0].command = kPS2C_WriteCommandPort;
447: request->commands[0].inOrOut = kCP_TransmitToMouse;
448: request->commands[1].command = kPS2C_WriteDataPort;
449: request->commands[1].inOrOut = kDP_GetId;
450: request->commands[2].command = kPS2C_ReadDataPortAndCompare;
451: request->commands[2].inOrOut = kSC_Acknowledge;
452: request->commands[3].command = kPS2C_ReadDataPort;
453: request->commands[3].inOrOut = 0;
454: request->commandsCount = 4;
455: _device->submitRequestAndBlock(request);
456:
457: if (request->commandsCount == 4) // success?
458: returnValue = request->commands[3].inOrOut;
459:
460: _device->freeRequest(request);
461:
462: return returnValue;
463: }
464:
465: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
466:
467: void ApplePS2Mouse::setCommandByte(UInt8 setBits, UInt8 clearBits)
468: {
469: //
470: // Sets the bits setBits and clears the bits clearBits "atomically" in the
471: // controller's Command Byte. Since the controller does not provide such
472: // a read-modify-write primitive, we resort to a test-and-set try loop.
473: //
474: // Do NOT issue this request from the interrupt/completion context.
475: //
476:
477: UInt8 commandByte;
478: UInt8 commandByteNew;
479: PS2Request * request = _device->allocateRequest();
480:
481: do
482: {
483: // (read command byte)
484: request->commands[0].command = kPS2C_WriteCommandPort;
485: request->commands[0].inOrOut = kCP_GetCommandByte;
486: request->commands[1].command = kPS2C_ReadDataPort;
487: request->commands[1].inOrOut = 0;
488: request->commandsCount = 2;
489: _device->submitRequestAndBlock(request);
490:
491: //
492: // Modify the command byte as requested by caller.
493: //
494:
495: commandByte = request->commands[1].inOrOut;
496: commandByteNew = (commandByte | setBits) & (~clearBits);
497:
498: // ("test-and-set" command byte)
499: request->commands[0].command = kPS2C_WriteCommandPort;
500: request->commands[0].inOrOut = kCP_GetCommandByte;
501: request->commands[1].command = kPS2C_ReadDataPortAndCompare;
502: request->commands[1].inOrOut = commandByte;
503: request->commands[2].command = kPS2C_WriteCommandPort;
504: request->commands[2].inOrOut = kCP_SetCommandByte;
505: request->commands[3].command = kPS2C_WriteDataPort;
506: request->commands[3].inOrOut = commandByteNew;
507: request->commandsCount = 4;
508: _device->submitRequestAndBlock(request);
509:
510: //
511: // Repeat this loop if last command failed, that is, if the old command byte
512: // was modified since we first read it.
513: //
514:
515: } while (request->commandsCount != 4);
516:
517: _device->freeRequest(request);
518: }
519:
520: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
521:
522: void ApplePS2Mouse::accelerationTable(IOHIAccelerationPoint ** table,
523: IOItemCount * numEntries)
524: {
525: static IOHIAccelerationPoint defaultTable[] =
526: {
527: { 0x0000000, 0x000000 },
528: { 0x000713b, 0x006000 },
529: { 0x0010000, 0x010000 },
530: { 0x0044ec5, 0x108000 },
531: { 0x00c0000, 0x5f0000 },
532: { 0x016ec4f, 0x8b0000 },
533: { 0x01d3b14, 0x948000 },
534: { 0x0227627, 0x960000 },
535: { 0x7ffffff, 0x960000 }
536: };
537:
538: *table = defaultTable;
539: *numEntries = sizeof(defaultTable) / sizeof(defaultTable[0]);
540: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.