/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.sound.speaker.pc; import java.security.PrivilegedExceptionAction; import javax.naming.NameNotFoundException; import org.jnode.driver.Device; import org.jnode.driver.Driver; import org.jnode.driver.DriverException; import org.jnode.driver.sound.speaker.Note; import org.jnode.driver.sound.speaker.SpeakerAPI; import org.jnode.naming.InitialNaming; import org.jnode.system.resource.IOResource; import org.jnode.system.resource.ResourceManager; import org.jnode.system.resource.ResourceNotFreeException; import org.jnode.system.resource.ResourceOwner; import org.jnode.util.AccessControllerUtils; /** * A driver for the internal speaker of a IBM Compatable machine. * * @author Matt Paine */ public class PCSpeakerDriver extends Driver implements SpeakerAPI { // ********** constants **********// /** The port for the speaker * */ public static final int SPEAKER_PORT = 0x61; /** The PIT Control Port * */ public static final int CONTROL_PORT = 0x43; /** The PIT Channel 2 Port * */ public static final int CHANNEL2_PORT = 0x42; /** The base frequency for the PIT * */ public static final int BASE_FREQUENCY = 1193100; // ********** private variables **********// /** This holds the reference to the IOResource we need to manipulate. * */ private IOResource speakIO; /** This holds the reference to the IOResource for the PIT * */ private IOResource pitIO; // ********** Driver implementation **********// /** A routine that claims all the resources nessasary to run the PCSpeaker. * */ public void startDevice() throws DriverException { try { final Device dev = getDevice(); final ResourceManager rm = InitialNaming.lookup(ResourceManager.NAME); speakIO = claimPorts(rm, dev, SPEAKER_PORT, 1); pitIO = claimPorts(rm, dev, CHANNEL2_PORT, 2); getDevice().registerAPI(SpeakerAPI.class, this); // do a test beep during startup // beep(); } catch (NameNotFoundException nnfex) { throw new DriverException(nnfex); } catch (ResourceNotFreeException rnfex) { throw new DriverException(rnfex); } } /** A routine that releases all the resources back to the operating system. * */ public void stopDevice() throws DriverException { noSound(); getDevice().unregisterAPI(SpeakerAPI.class); pitIO.release(); speakIO.release(); } // ********** Speaker implementation **********// public void beep() { // backup the port, and start the beep int oldPort = speakIO.inPortByte(SPEAKER_PORT); int newValue = oldPort | 0x03; // 0b0000_0011; speakIO.outPortByte(SPEAKER_PORT, newValue); // sleep for the duration of the beep try { Thread.sleep(125); } catch (InterruptedException iex) { //empty } // restore the speaker port speakIO.outPortByte(SPEAKER_PORT, oldPort); } public void playNote(Note n) { pitIO.outPortByte(CONTROL_PORT, 0xb6); playNote(n.getNote(), n.getLength()); } public void playNote(Note[] n) { pitIO.outPortByte(CONTROL_PORT, 0xb6); for (int x = 0; x < n.length; x++) playNote(n[x].getNote(), n[x].getLength()); } public void playNote(int frequency, int length) { int freq = (BASE_FREQUENCY / frequency); pitIO.outPortByte(CHANNEL2_PORT, (byte) (freq & 0xff)); pitIO.outPortByte(CHANNEL2_PORT, (byte) (freq >> 8)); // backup the port, and start the beep int oldPort = speakIO.inPortByte(SPEAKER_PORT); int newValue = oldPort | 0x03; // 0b0000_0011; speakIO.outPortByte(SPEAKER_PORT, newValue); // sleep for the duration of the beep try { Thread.sleep(length); } catch (InterruptedException iex) { //empty } // restore the speaker port speakIO.outPortByte(SPEAKER_PORT, oldPort); } public void noSound() { int val = speakIO.inPortByte(SPEAKER_PORT); speakIO.outPortByte(SPEAKER_PORT, val & 0xFC); } private IOResource claimPorts(final ResourceManager rm, final ResourceOwner owner, final int low, final int length) throws ResourceNotFreeException, DriverException { try { return AccessControllerUtils.doPrivileged(new PrivilegedExceptionAction<IOResource>() { public IOResource run() throws ResourceNotFreeException { return rm.claimIOResource(owner, low, length); } }); } catch (ResourceNotFreeException ex) { throw ex; } catch (Exception ex) { throw new DriverException("Unknown exception", ex); } } }