changeset 95:5ac0112afff2

8071998: [DIO1.0.1] SPIDevice update Summary: Transactional is optional interface from now Reviewed-by: alkonsta
author snazarki
date Mon, 02 Feb 2015 13:50:33 +0400
parents 6650624647cf
children 42f369831eaa
files src/share/classes/com/oracle/dio/impl/Transaction.java src/share/classes/com/oracle/dio/spibus/impl/SPICompositeMessageImpl.java src/share/classes/com/oracle/dio/spibus/impl/SPISlaveImpl.java src/share/classes/jdk/dio/spibus/SPICompositeMessage.java src/share/classes/jdk/dio/spibus/SPIDevice.java src/share/classes/jdk/dio/spibus/SPIDeviceConfig.java src/share/classes/jdk/dio/spibus/package-info.java src/share/native/com/oracle/dio/javacall_spi.h
diffstat 8 files changed, 694 insertions(+), 227 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/oracle/dio/impl/Transaction.java	Mon Feb 02 13:50:33 2015 +0400
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package com.oracle.dio.impl;
+import com.oracle.dio.power.impl.PowerManagedBase;
+
+import jdk.dio.Device;
+import jdk.dio.DeviceDescriptor;
+
+/**
+ * Dummy class for devices without Transactional support.
+ *
+ */
+public abstract class Transaction<P extends Device<P>> extends PowerManagedBase<P>{
+
+    public static final int REGULAR_MESSAGE = -1;
+
+    protected int transaction = REGULAR_MESSAGE;
+
+    protected Transaction(DeviceDescriptor<P> dscr, int mode) {
+        super(dscr, mode);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/oracle/dio/spibus/impl/SPICompositeMessageImpl.java	Mon Feb 02 13:50:33 2015 +0400
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.dio.spibus.impl;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import com.oracle.dio.utils.ExceptionMessage;
+
+import jdk.dio.ClosedDeviceException;
+import jdk.dio.UnavailableDeviceException;
+import jdk.dio.spibus.SPICompositeMessage;
+import jdk.dio.spibus.SPIDevice;
+
+
+final class SPICompositeMessageImpl implements SPICompositeMessage {
+
+    private ArrayList<Message> messageList = new ArrayList<>();
+
+    private boolean isAlreadyTransferedOnce;
+
+    /* Owner of the message */
+    private SPISlaveImpl device;
+
+    // delay between operations
+    private int delay;
+
+    private class Message {
+        ByteBuffer tx, rx;
+        int skip, delay;
+        public Message(ByteBuffer tx, int skip, ByteBuffer rx, int delay) {
+            this.rx = rx;
+            this.skip = skip;
+            this.tx = tx;
+            this.delay = delay;
+        }
+    }
+
+    void check(Message message) throws ClosedDeviceException {
+
+        if (isAlreadyTransferedOnce) {
+            throw new IllegalStateException(
+                ExceptionMessage.format(ExceptionMessage.I2CBUS_ALREADY_TRANSFERRED_MESSAGE)
+            );
+        }
+
+        if (0 > message.skip) {
+            throw new IllegalArgumentException(
+                ExceptionMessage.format(ExceptionMessage.I2CBUS_NEGATIVE_SKIP_ARG)
+            );
+        }
+
+        if (!device.isOpen()) {
+            throw new ClosedDeviceException();
+        }
+
+        for (int i = 0; i < messageList.size(); i++) {
+            ByteBuffer tx = messageList.get(i).tx;
+            ByteBuffer rx = messageList.get(i).rx;
+            if (    (null != tx && (tx == message.tx ||
+                                    rx == message.tx) )
+                 || (null != rx && (tx == message.rx ||
+                                    rx == message.rx ) ) ) {
+                throw new IllegalArgumentException(
+                    ExceptionMessage.format(ExceptionMessage.I2CBUS_BUFFER_GIVEN_TWICE)
+                );
+            }
+        }
+    }
+
+    /**
+     * Creates a new {@code SPICompositeMessageImpl} instance.
+     */
+    SPICompositeMessageImpl(SPISlaveImpl device) {
+        this.device = device;
+    }
+
+    @Override
+    public SPICompositeMessage appendRead(ByteBuffer rxBuf)  throws IOException, ClosedDeviceException {
+        return appendRead(0, rxBuf);
+    }
+
+    @Override
+    public SPICompositeMessage appendRead(int rxSkip, ByteBuffer rxBuf) throws IOException, ClosedDeviceException {
+        device.checkBuffer(rxBuf);
+        return append(null, rxSkip, rxBuf);
+    }
+
+    @Override
+    public SPICompositeMessage appendWrite( ByteBuffer txBuf) throws IOException,
+            ClosedDeviceException {
+        device.checkBuffer(txBuf);
+        return append(txBuf, 0, null);
+    }
+
+    @Override
+    public SPICompositeMessage appendWriteAndRead(ByteBuffer src, ByteBuffer dst) throws IOException, ClosedDeviceException {
+        return appendWriteAndRead(src, 0, dst);
+    }
+
+    @Override
+    public SPICompositeMessage appendWriteAndRead(ByteBuffer src, int skip, ByteBuffer dst) throws IOException, ClosedDeviceException{
+        device.checkBuffer(src);
+        device.checkBuffer(dst);
+        return append(src,skip,dst);
+    }
+
+    private SPICompositeMessage append(ByteBuffer src, int skip, ByteBuffer dst)  throws IOException, ClosedDeviceException {
+        Message message = new Message(src, skip, dst, delay);
+        check(message);
+        messageList.add(message);
+        return this;
+    }
+
+    @Override
+    public synchronized SPICompositeMessage appendDelay(int delay) {
+        this.delay = delay;
+        return this;
+    }
+
+    @Override
+    public SPIDevice getTargetedDevice() {
+        return device;
+    }
+
+    @Override
+    public int[] transfer() throws IOException, UnavailableDeviceException, ClosedDeviceException {
+        int bytesRead[];
+
+        // global handle lock to prevent access from other threads.
+        synchronized (device.getHandle()) {
+            /* Forbid adding more messages to this combined message */
+            isAlreadyTransferedOnce = true;
+            if (0 == messageList.size()) {
+                notifyAll();
+                return null;
+            }
+
+            int transaction = device.beginTransaction();
+
+            try {
+                final int size = messageList.size();
+                bytesRead = new int[size];
+
+                for (int i = 0; i < size; i++) {
+                    Message message = messageList.get(i);
+                    int res = device.transfer(message.tx, message.skip, message.rx, transaction);
+                    if (null != message.rx) {
+                        bytesRead[i] = res;
+                    }
+                }
+
+            } finally {
+                device.endTransaction(transaction);
+                notifyAll();
+            }
+
+        }
+        return bytesRead;
+    }
+}
--- a/src/share/classes/com/oracle/dio/spibus/impl/SPISlaveImpl.java	Mon Feb 02 13:46:41 2015 +0400
+++ b/src/share/classes/com/oracle/dio/spibus/impl/SPISlaveImpl.java	Mon Feb 02 13:50:33 2015 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,13 @@
 package com.oracle.dio.spibus.impl;
 
 import java.io.IOException;
+import java.lang.Runnable;
 import java.nio.ByteBuffer;
 import java.security.AccessController;
+import java.util.Objects;
 import java.util.Vector;
-import java.lang.Runnable;
 
+import com.oracle.dio.impl.Transaction;
 import com.oracle.dio.power.impl.PowerManagedBase;
 import com.oracle.dio.utils.Constants;
 import com.oracle.dio.utils.ExceptionMessage;
@@ -44,6 +46,7 @@
 import jdk.dio.DevicePermission;
 import jdk.dio.InvalidDeviceConfigException;
 import jdk.dio.InvalidDeviceConfigException;
+import jdk.dio.Transactional;
 import jdk.dio.UnavailableDeviceException;
 import jdk.dio.spibus.InvalidWordLengthException;
 import jdk.dio.spibus.InvalidWordLengthException;
@@ -55,17 +58,15 @@
 /**
  *Implementation of SPISlave Interface.
  */
-class SPISlaveImpl extends PowerManagedBase<SPIDevice> implements SPIDevice {
+class SPISlaveImpl extends Transaction<SPIDevice> implements SPIDevice {
 
     //every call checkWordLen updates these two variables
     private int byteNum;
     private int bitNum;
 
-    // indicate transaction is ongoing
-    private Vector<Runnable> pendingActions;
 
     public SPISlaveImpl(DeviceDescriptor<SPIDevice> dscr, int mode) throws
-            DeviceNotFoundException, InvalidDeviceConfigException {
+            IOException, DeviceNotFoundException, InvalidDeviceConfigException {
         super(dscr, mode);
 
         SPIDeviceConfig cfg = dscr.getConfiguration();
@@ -84,6 +85,19 @@
                                         cfg.getBitOrdering(), mode == DeviceManager.EXCLUSIVE);
 
         initPowerManagement();
+
+        bitNum = getWordLength0();
+        if (bitNum > Constants.MAX_WORD_LEN) {
+            throw new IOException (
+                ExceptionMessage.format(ExceptionMessage.SPIBUS_SLAVE_WORD_LENGTH, bitNum)
+            );
+        }
+        byteNum = (bitNum - 1)/8 + 1;
+    }
+
+    @Override
+    public jdk.dio.spibus.SPICompositeMessage createCompositeMessage() {
+        return new SPICompositeMessageImpl(this);
     }
 
     private String getSecurityName(){
@@ -104,36 +118,6 @@
         AccessController.checkPermission(permission);
     }
 
-    @Override
-    public synchronized void begin() throws IOException,
-            UnavailableDeviceException, ClosedDeviceException {
-        checkPowerState();
-        tryLock(1);
-        try {
-            begin0();
-            pendingActions = new Vector<>(2);
-        } catch (IOException | IllegalStateException e) {
-            unlock();
-            throw e;
-        }
-    }
-
-    @Override
-    public synchronized void end() throws IOException,
-            UnavailableDeviceException, ClosedDeviceException {
-        checkOpen();
-        try {
-            end0();
-            for (Runnable toRun : pendingActions) {
-                toRun.run();
-            }
-        } finally {
-            // release all ByteBuffers
-            pendingActions = null;
-            unlock();
-        }
-    }
-
     /**
      * Gets the transfer word length in bits supported by this slave device.
      * <p>
@@ -172,10 +156,6 @@
     @Override
     public int read() throws IOException, UnavailableDeviceException,
             ClosedDeviceException {
-        synchronized(this) {
-            checkPowerState();
-            checkWordLen();
-        }
         ByteBuffer dst = ByteBuffer.allocateDirect(byteNum);
         transfer(null, 0, dst);
         return byteArray2int(dst);
@@ -242,11 +222,6 @@
         if (0 > skip) {
             throw new IllegalArgumentException();
         }
-        synchronized(this) {
-            checkPowerState();
-            checkWordLen();
-            checkBuffer(dst);
-        }
         return transfer(null, skip, dst);
     }
 
@@ -270,11 +245,6 @@
     @Override
     public int write(ByteBuffer src) throws IOException,
             UnavailableDeviceException, ClosedDeviceException {
-        synchronized(this) {
-            checkPowerState();
-            checkWordLen();
-            checkBuffer(src);
-        }
         return transfer(src, 0, null);
     }
 
@@ -299,32 +269,6 @@
         writeAndRead(txData);
     }
 
-    /**
-     * Exchanges (transmits and receives) data with this slave device.
-     * <p />
-     * The designated portions of the sending and receiving byte buffers may not have the same length. When sending more
-     * than is being received the extra received bytes are ignored/discarded. Conversely, when sending less than is
-     * being received extra dummy data will be sent.
-     * <p />
-     * This method behaves as a combined {@link SPIDevice#write(java.nio.ByteBuffer)} and
-     * {@link SPIDevice#read(java.nio.ByteBuffer)}.
-     *
-     * @param src
-     *            The buffer from which bytes are to be retrieved
-     * @param dst
-     *            The buffer into which bytes are to be transferred
-     * @return The number of bytes read, possibly zero, or {@code -1} if the device has reached end-of-stream
-     * @throws NullPointerException
-     *             If {@code src} or {@code dst} is {@code null}.
-     * @throws InvalidWordLengthException
-     *             if the number of bytes to receive or send belies word length.
-     * @throws UnavailableDeviceException
-     *             if this peripheral is not currently available - such as it is locked by another application.
-     * @throws ClosedDeviceException
-     *             if the peripheral has been closed.
-     * @throws IOException
-     *             If some other I/O error occurs
-     */
     @Override
     public int writeAndRead(ByteBuffer src, ByteBuffer dst)
             throws IOException, UnavailableDeviceException,
@@ -332,34 +276,6 @@
         return writeAndRead(src, 0, dst);
     }
 
-    /**
-     * Exchanges (transmits and receives) data with this slave device skipping the specified number of bytes received.
-     * <p />
-     * The designated portions of the sending and receiving byte buffers may not have the same length. When sending more
-     * than is being received the extra received bytes are ignored/discarded. Conversely, when sending less than is
-     * being received extra dummy data will be sent.
-     * <p />
-     * This method behaves as a combined {@link SPIDevice#write(java.nio.ByteBuffer)} and
-     * {@link SPIDevice#read(java.nio.ByteBuffer)}.
-     *
-     * @param src
-     *            The buffer from which bytes are to be retrieved
-     * @param skip
-     *            the number of received bytes that must be ignored/skipped before filling in the {@code dst} buffer.
-     * @param dst
-     *            The buffer into which bytes are to be transferred
-     * @return The number of bytes read, possibly zero, or {@code -1} if the device has reached end-of-stream
-     * @throws NullPointerException
-     *             If {@code src} or {@code dst} is {@code null}.
-     * @throws InvalidWordLengthException
-     *             if the total number of bytes to receive or send belies word length.
-     * @throws UnavailableDeviceException
-     *             if this peripheral is not currently available - such as it is locked by another application.
-     * @throws ClosedDeviceException
-     *             if the peripheral has been closed.
-     * @throws IOException
-     *             If some other I/O error occurs
-     */
     @Override
     public int writeAndRead(ByteBuffer src, int skip, ByteBuffer dst)
             throws IOException, UnavailableDeviceException,
@@ -367,12 +283,6 @@
         if (0 > skip) {
             throw new IllegalArgumentException();
         }
-        synchronized(this) {
-            checkPowerState();
-            checkWordLen();
-            checkBuffer(src);
-            checkBuffer(dst);
-        }
         return transfer(src, skip, dst);
     }
 
@@ -394,10 +304,6 @@
      */
     @Override
     public int writeAndRead(int txData) throws IOException, UnavailableDeviceException, ClosedDeviceException{
-        synchronized(this) {
-            checkPowerState();
-            checkWordLen();
-        }
         ByteBuffer tx = int2byteArray(txData);
         ByteBuffer rx = tx.slice();
         transfer(tx, 0, rx);
@@ -420,24 +326,9 @@
         throw new java.lang.UnsupportedOperationException();
     }
 
-
-    private void checkWordLen(){
-        bitNum = getWordLength0();
-        if (bitNum > Constants.MAX_WORD_LEN) {
-            throw new InvalidWordLengthException(
-                ExceptionMessage.format(ExceptionMessage.SPIBUS_SLAVE_WORD_LENGTH, bitNum)
-            );
-        }
-        byteNum = (bitNum - 1)/8 + 1;
-    }
-
     // checkWordLen ought to be called before checkBuffer to get byteNum is up to date
-    private void checkBuffer(ByteBuffer buffer) {
-        if (buffer == null){
-            throw new NullPointerException(
-                ExceptionMessage.format(ExceptionMessage.SPIBUS_NULL_BUFFER)
-            );
-        }
+    void checkBuffer(ByteBuffer buffer) {
+        Objects.requireNonNull(buffer, ExceptionMessage.format(ExceptionMessage.SPIBUS_NULL_BUFFER));
 
         if ((buffer.remaining() % byteNum) != 0) {
             throw new InvalidWordLengthException(
@@ -466,12 +357,27 @@
         return retI;
     }
 
+    private int transfer(ByteBuffer src, int skip, ByteBuffer dst) throws IOException {
+        return transfer(src, skip, dst, transaction);
+    }
+
     /* Returns number of recevied bytes if dst is not NULL, or number of sent bytes otherwise */
-    private int transfer(ByteBuffer src, int skip, ByteBuffer dst) throws IOException {
+    int transfer(ByteBuffer src, int skip, ByteBuffer dst, int transaction) throws IOException {
+
+        synchronized(this) {
+            checkPowerState();
+            if (null != src) {
+                checkBuffer(src);
+            }
+            if (null != dst) {
+                checkBuffer(dst);
+            }
+        }
+
         int xfered = 0;
         final boolean count_recv = null != dst;
         final boolean combined = (0 != skip || (null != dst && null != src && dst.remaining() != src.remaining()));
-        Vector<Runnable> localActions;
+        Vector<Runnable> localActions = null;
 
         /* synchronized allows to avoid IllegaStateException for the case when transfer()
            is called while previous operation is incomplete.
@@ -479,17 +385,13 @@
         */
         synchronized(handle){
 
-        synchronized(this) {
-            localActions = pendingActions;
-        }
-        final boolean trStart = combined && null == localActions;
+        final boolean trStart = combined && transaction != Transaction.REGULAR_MESSAGE;
 
         if (trStart) {
-            try {
-                begin();
-                localActions = pendingActions;
-            } catch (UnsupportedOperationException e) {
-                Logging.reportWarning("Combined message is unsupported. Continue...");
+            // can throw ISE
+            transaction = beginTransaction();
+            if (!(this instanceof Transactional)) {
+                localActions = new Vector<>();
             }
         }
 
@@ -520,33 +422,27 @@
 
                 try {
                     conditionalLock();
-                     writeAndRead0(toSend, toRecv);
+                    writeAndRead0(toSend, toRecv);
                 } finally {
                     conditionalUnlock();
                 }
 
                 if (null != src) {
+
                     if (null != localActions) {
                         final ByteBuffer ref = toSend;
                         localActions.add(new Runnable() {
                                 public void run() {
-                                    // dummy action to keep refence in queue
+                                    // dummy action to retain object refence
                                     ref.remaining();
                                 };
                             });
                     }
 
-                    try {
-                        if (!count_recv) {
-                            xfered += toSend.remaining();
-                        }
-                        src.position(src.position() + toSend.remaining());
-                    }catch (IllegalArgumentException e){
-                        // the buffer was updated in parallel
-                        Logging.reportWarning(ExceptionMessage.format(ExceptionMessage.BUFFER_IS_MODIFIED));
-                        //
-                        src.position(src.limit());
+                    if (!count_recv) {
+                        xfered += toSend.remaining();
                     }
+                    shiftBufferPosition(src, src.position() + toSend.remaining());
                 }
 
                 if (skip > 0) {
@@ -560,6 +456,7 @@
                 }
                 if (null != toRecv) {
                     xfered += toRecv.remaining();
+                    // linux and similar accumulate packets and transfer them after endTrasaction call
                     // transaction requires postponed reverse copying
                     if (null != localActions) {
                         final ByteBuffer to = dst.slice();
@@ -589,8 +486,12 @@
         } finally  {
             if (trStart) {
                 try {
-                    // will initiate transfer on some platfroms
-                    end();
+                    endTransaction(transaction);
+                    if (null != localActions) {
+                        for (Runnable toRun: localActions) {
+                            toRun.run();
+                        }
+                    }
                 } catch (IllegalStateException e) {
                     // intentionally skip
                 }
@@ -600,6 +501,32 @@
         return xfered;
     }
 
+    // transaction demarcator
+    private static int trans_counter;
+
+    protected int beginTransaction() throws IOException, IllegalStateException {
+        // interapp lock
+        conditionalLock();
+
+        begin0();
+        // it is enough to separate transactions in scope of current application enviroment.
+        // the rest is cared by javacall
+        synchronized(SPISlaveImpl.class) {
+            return trans_counter++;
+        }
+    }
+
+    protected void endTransaction(int transaction) throws IllegalStateException {
+        if (transaction != this.transaction) {
+            throw new IllegalStateException();
+        }
+
+        end0();
+
+        // interapp unlock
+        conditionalUnlock();
+    }
+
     @Local(DontRemoveFields = {
         "com.oracle.dio.impl.Handle.native_handle",
         "com.oracle.dio.impl.AbstractPeripheral.handle",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/jdk/dio/spibus/SPICompositeMessage.java	Mon Feb 02 13:50:33 2015 +0400
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.dio.spibus;
+
+import jdk.dio.ClosedDeviceException;
+import jdk.dio.UnavailableDeviceException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * The {@code SPICompositeMessage} interface provides methods for constructing a
+ * composite message. A composite message may be constituted of a sequence of read
+ * and/or write operations to a single SPI slave device that will be performed as
+ * a single transaction.
+ * <p />
+ * Here is an example of a composite message to a single slave: <blockquote>
+ *
+ * <pre>
+ * try (SPIDevice slave = DeviceManager.open("SPI1", SPIDevice.class, null)) {
+ *    ByteBuffer sndBuf1 = ByteBuffer.wrap(new byte[] {0x01});
+ *    ByteBuffer sndBuf2 = ByteBuffer.wrap(new byte[] {0x02});
+ *    ByteBuffer rcvBuf = ByteBuffer.wrap(new byte[3]);
+ *    int bytesRead = slave.createCompositeMessage()
+ *             .appendwrite(sndBuf1)
+ *             .appendDelay(100)
+ *             .appendwriteAndRead(sndBuf2, rcvBuf)
+ *             .transfer()[2];
+ * } catch (IOException ioe) {
+ *     // Handle exception
+ * }
+ * </pre>
+ * </blockquote> The preceding example is using a
+ * <em>try-with-resources</em> statement; the
+ * {@link SPIDevice#close SPIDevice.close} method is automatically invoked by
+ * the platform at the end of the statement.
+ *
+ * @since 1.0.1
+ */
+public interface SPICompositeMessage {
+
+    /**
+     * Appends a read message/operation from the targeted SPI slave device.
+     * Reads up to {@code rxBuf.remaining()} bytes of data from the targeted slave
+     * device into the buffer {@code rxBuf}.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the appended operation will have a behavior equivalent to that of the invocation of the
+     * {@link SPIDevice#read(java.nio.ByteBuffer)} method on the targeted {@code SPIDevice}.
+     * <p />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffer until the operation has completed - that
+     * is: until the {@code transfer} method has been invoked and has returned.
+     *
+     * @param rxBuf the buffer into which the data is read.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws NullPointerException if {@code rxBuf} is {@code null}.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IOException if some other I/O error occurs.
+     */
+    SPICompositeMessage appendRead(ByteBuffer rxBuf) throws IOException, ClosedDeviceException;
+
+    /**
+     * Appends a read message/operation from the targeted SPI slave device.
+     * Reads up to {@code rxBuf.remaining()} bytes of data from the targeted slave
+     * device into the buffer skipping {@code rxBuf} the first {@code rxSkip}
+     * bytes read.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the appended operation will have a behavior equivalent to that of the invocation of the
+     * {@link SPIDevice#read(int, java.nio.ByteBuffer)} method on the targeted {@code SPIDevice}.
+     * <p />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffer until the operation has completed - that
+     * is: until the {@code transfer} method has been invoked and has returned.
+     *
+     * @param rxSkip the number of read bytes that must be ignored/skipped
+     * before filling in the {@code rxBuf} buffer.
+     * @param rxBuf the buffer into which the data is read.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws NullPointerException if {@code rxBuf} is {@code null}.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IllegalArgumentException if {@code rxSkip} is negative.
+     * @throws IOException if some other I/O error occurs.
+     */
+    SPICompositeMessage appendRead(int rxSkip, ByteBuffer rxBuf) throws IOException, ClosedDeviceException;
+
+    /**
+     * Appends a write message/operation from the targeted SPI slave device.
+     * Writes to the targeted slave device {@code txBuf.remaining()} bytes from the
+     * buffer {@code txBuf}.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the appended operation will have a behavior equivalent to that of the invocation of the
+     * {@link SPIDevice#write(java.nio.ByteBuffer)} method on the targeted {@code SPIDevice}.
+     * <p />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffer until the operation has completed - that
+     * is: until the {@code transfer} method has been invoked and has returned.
+     *
+     * @param txBuf the buffer containing the bytes to write.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws NullPointerException if {@code txBuf} is {@code null}.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IOException if some other I/O error occurs.
+     */
+    SPICompositeMessage appendWrite(ByteBuffer txBuf) throws IOException, ClosedDeviceException;
+
+    /**
+     * Appends an exchange message/operation from the targeted SPI slave device.
+     * Exchanges (transmits and receives) data with the targeted slave device.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the appended operation will have a behavior equivalent to that of the invocation of the
+     * {@link SPIDevice#writeAndRead(java.nio.ByteBuffer, java.nio.ByteBuffer)}
+     * method on the targeted {@code SPIDevice}.
+     * <p />
+     * The designated portions of the sending and receiving byte buffers may not have the same length. When sending more
+     * than is being received the extra received bytes are ignored/discarded. Conversely, when sending less than is
+     * being received extra dummy data will be sent.
+     * <p />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffer until the operation has completed - that
+     * is: until the {@code transfer} method has been invoked and has returned.
+     *
+     * @param src
+     *            The buffer from which bytes are to be retrieved.
+     * @param dst
+     *            The buffer into which bytes are to be transferred.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws NullPointerException
+     *             if {@code src} or {@code dst} is {@code null}.
+     * @throws InvalidWordLengthException
+     *             if the number of bytes to receive or send belies word length.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IOException if some other I/O error occurs
+     */
+    SPICompositeMessage appendWriteAndRead(ByteBuffer src, ByteBuffer dst) throws IOException, ClosedDeviceException;
+
+    /**
+     * Appends an exchange message/operation with the targeted SPI slave device.
+     * Exchanges (transmits and receives) data with the targeted slave device skipping the specified number of bytes received.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the appended operation will have a behavior equivalent to that of the invocation of the
+     * {@link SPIDevice#writeAndRead(java.nio.ByteBuffer, int, java.nio.ByteBuffer)}
+     * method on the targeted {@code SPIDevice}.
+     * <p />
+     * The designated portions of the sending and receiving byte buffers may not have the same length. When sending more
+     * than is being received the extra received bytes are ignored/discarded. Conversely, when sending less than is
+     * being received extra dummy data will be sent.
+     * <p />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffer until the operation has completed - that
+     * is: until the {@code transfer} method has been invoked and has returned.
+     *
+     * @param src
+     *            The buffer from which bytes are to be retrieved.
+     * @param skip
+     *            the number of received bytes that must be ignored/skipped before filling in the {@code dst} buffer.
+     * @param dst
+     *            The buffer into which bytes are to be transferred.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws NullPointerException
+     *             if {@code src} or {@code dst} is {@code null}.
+     * @throws IllegalArgumentException
+     *              if {@code skip} is negative.
+     * @throws InvalidWordLengthException
+     *             if the number of bytes to receive or send belies word length.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IOException
+     *             if some other I/O error occurs
+     */
+    SPICompositeMessage appendWriteAndRead(ByteBuffer src, int skip, ByteBuffer dst) throws IOException, ClosedDeviceException;
+
+    /**
+     * Appends a delay (in microseconds).
+     * Delays the next appended operation by the specified amount of microseconds.
+     * <p />
+     * Upon the invocation of the {@link #transfer transfer} method
+     * the next operation (or the completion of this composite message transfer if this
+     * is the last operation) will be delayed by the specified amount of microseconds.
+     * <p />
+     * If the underlying platform or driver does not support a microsecond timer resolution
+     * or does not support the requested delay value then {@code delay} will be <em>rounded up</em>
+     * to accommodate the supported timer resolution or the closest greater supported discrete delay value, if any.
+     *
+     * @param delay
+     *            the amount (in microseconds) to delay the next operation.
+     * @return a reference to this {@code SPICompositeMessage} object.
+     * @throws IllegalArgumentException
+     *              if {@code delay} is negative or cannot be accommodated for.
+     * @throws IllegalStateException if this message has already been assembled
+     * and transferred once.
+     * @throws ClosedDeviceException if the device has been closed.
+     * @throws IOException
+     *             if some other I/O error occurs
+     */
+    SPICompositeMessage appendDelay(int delay)  throws IOException, ClosedDeviceException;
+
+    /**
+     * Transfers this composite message to the targeted {@code SPIDevice}. This will result in each of the
+     * contained messages/operations to be sent/executed in the same order they
+     * have been appended to this composite message.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a transaction
+     * (see {@link jdk.dio.Transactional}) or, a read or write operation upon the targeted slave device,
+     * however, then an invocation of this method will block until the first operation is complete.
+     * <p />
+     * Once transferred no additional operation can be appended anymore to this
+     * composite message. Any such attempt will result in a
+     * {@link IllegalStateException} to be thrown.
+     * Nevertheless, this {@code SPICompositeMessage} object can be reused several times to perform
+     * the same sequence of operations. The data transferred
+     * to or from each of the provided {@code ByteBuffer}s is determined by their respective current {@code position}
+     * and {@code remaining} attributes at the time this method is call.
+     * <br />
+     * Buffers are not safe for use by multiple concurrent threads so care should
+     * be taken to not access the provided buffers until the transfer has completed.
+     *
+     * @return an array containing the number of bytes read for each of the read
+     * operations of this composite message; the results of each read operations
+     * appear in the very same order the read operations have been appended to
+     * this composite message.
+     * @throws InvalidWordLengthException if the total number of bytes to receive
+     * or send of any of the appended operations belies word length.
+     * @throws UnavailableDeviceException if the targeted devices is not
+     * currently available - such as it is locked by another application.
+     * @throws ClosedDeviceException if the targeted device is has been closed.
+     * @throws IOException if some other I/O error occurred
+     */
+    int[] transfer() throws IOException, UnavailableDeviceException, ClosedDeviceException;
+
+    /**
+     * Gets the {@code SPIDevice} this composite message is targeting.
+     * @return the targeted SPI device slave.
+     */
+    SPIDevice getTargetedDevice();
+}
--- a/src/share/classes/jdk/dio/spibus/SPIDevice.java	Mon Feb 02 13:46:41 2015 +0400
+++ b/src/share/classes/jdk/dio/spibus/SPIDevice.java	Mon Feb 02 13:50:33 2015 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@
 import jdk.dio.DeviceManager;
 import jdk.dio.ClosedDeviceException;
 import jdk.dio.UnavailableDeviceException;
-import jdk.dio.Transactional;
 import java.io.IOException;
 import java.nio.*;
 import java.nio.channels.ByteChannel;
@@ -71,55 +70,48 @@
  * buffer must be such that: <br />
  * <em>((l % (((w - 1) / 8) + 1)) == 0)</em>
  * <p />
- * Since the SPI master device controls the serial transmission clock read and write operations are non-blocking
- * (unless another read or write operation is already on-going in a different thread on the same {@code SPIDevice} instance).
- * It is the responsibility of the application to appropriately control the timing between a call to the {@link #begin begin} method which
- * may assert the Chip Select (depending on the configuration, see {@link SPIDeviceConfig#CS_NOT_CONTROLLED}) and
- * subsequent calls to the {@link #read read}, {@link #write write} and {@link #writeAndRead writeAndRead} methods.
+ * Since the SPI master device controls the serial transmission clock read and write operations are never blocked nor delayed by
+ * unresponsive slave devices. Not though that a read or write operation may be blocked if another read or write operation
+ * is concurrently being performed on the same {@code SPIDevice} instance.
  * <p />
  * When the data exchange is over, an application should call the {@link #close SPIDevice.close} method to close the
  * SPI slave device. Any further attempt to transmit/write or receive/read to/from an SPI slave device which has been
  * closed will result in a {@link ClosedDeviceException} been thrown.
+ * <h3>SPI Transactions</h3>
+ * Depending on the underlying platform and driver capabilities an {@code SPIDevice} instance may additionally implement
+ * the {@link jdk.dio.Transactional Transactional} interface to indicate that it supports SPI transactions. In such a case the {@link jdk.dio.Transactional#begin Transactional.begin}
+ * and {@link jdk.dio.Transactional#end Transactional.end} methods may be used to demarcate the beginning and the end of an SPI transaction.
+ * This typically results in the SPI slave's Select line (SS) remaining asserted during the whole sequence of read and write operations performed within the demarcated
+ * transaction. It is the responsibility of the application to appropriately control the timing between a call to the {@code begin} method which
+ * may assert the Chip Select (depending on the configuration, see {@link SPIDeviceConfig#CS_NOT_CONTROLLED}) and
+ * subsequent calls to the {@link #read read}, {@link #write write} and {@link #writeAndRead writeAndRead} methods.
+ * <p />
+ * An application can alternatively perform a sequence of reads and/or writes - from/to one or several slaves, that
+ * are guaranteed to be performed as a single transaction using an {@link SPICompositeMessage} object.
+ * <h3>Device Probing Limitations</h3>
+ * Opening an {@code SPIDevice} instance with hardware addressing information and configuration
+ * may be subject to <a href="{@docRoot}/jdk/dio/DeviceManager.html#probing">device probing limitations </a>.
  *
+ * @see jdk.dio.Transactional
  * @see SPIPermission
+ * @see SPICompositeMessage
  * @see InvalidWordLengthException
  * @see ClosedDeviceException
  * @since 1.0
  */
 @apimarker.API("device-io_1.0")
 @WeakDontRenameClass
-public interface SPIDevice extends Device<SPIDevice>, ByteChannel, Transactional, BufferAccess<ByteBuffer> {
+
+public interface SPIDevice extends Device<SPIDevice>, ByteChannel, BufferAccess<ByteBuffer> {
 
     /**
-     * Demarcates the beginning of an SPI transaction so that this slave's Select line (SS) will be remain asserted
-     * during the subsequent read and write operations and until the transaction ends.
+     * Creates a new {@code SPICompositeMessage} instance targeting this slave
+     * device.
      *
-     * @throws UnavailableDeviceException
-     *             if this device is not currently available - such as it is locked by another application.
-     * @throws ClosedDeviceException
-     *             if the device has been closed.
-     * @throws IOException
-     *             if some other I/O error occurs.
-     * @throws IllegalStateException
-     *             if a transaction is already in progress.
+     * @return a new {@code SPICompositeMessage} instance.
+     * @since 1.0.1
      */
-    @Override
-    void begin() throws IOException, UnavailableDeviceException, ClosedDeviceException;
-
-    /**
-     * Demarcates the end of a transaction hence ending the assertion of this slave's Select line (SS).
-     *
-     * @throws UnavailableDeviceException
-     *             if this device is not currently available - such as it is locked by another application.
-     * @throws ClosedDeviceException
-     *             if the device has been closed.
-     * @throws IOException
-     *             if some other I/O error occurs.
-     * @throws IllegalStateException
-     *             if a transaction is not currently in progress.
-     */
-    @Override
-    void end() throws IOException, UnavailableDeviceException, ClosedDeviceException;
+    SPICompositeMessage createCompositeMessage();
 
     /**
      * Gets the transfer word length in bits supported by this slave device.
@@ -139,6 +131,10 @@
 
     /**
      * Reads one data word of up to 32 bits from this slave device.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a read or write
+     * operation upon this slave device, however, then an invocation of this method will block until
+     * the first operation is complete.
      *
      * @return the data word read.
      * @throws IOException
@@ -158,15 +154,29 @@
      * <p />
      * Dummy data will be sent to this slave device by the platform.
      * <p />
-     * {@inheritDoc}
+     * An attempt is made to read up to <i>r</i> bytes from the device, where <i>r</i> is the number
+     * of bytes remaining in the buffer, that is, {@code dst.remaining()}, at the moment this method
+     * is invoked.
+     * <p />
+     * Suppose that a byte sequence of length <i>n</i> is read, where <i>{@code 0 <= n <= r}</i>.
+     * This byte sequence will be transferred into the buffer so that the first byte in the sequence
+     * is at index <i>p</i> and the last byte is at index <i>{@code p + n - 1}</i>, where <i>p</i>
+     * is the buffer's position at the moment this method is invoked. Upon return the buffer's
+     * position will be equal to <i>{@code p + n}</i>; its limit will not have changed.
+     * <p />
+     * A read operation will block until the requested <i>r</i> bytes are read.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a read or write
+     * operation upon this slave device, however, then an invocation of this method will block until
+     * the first operation is complete.
      *
      * @param dst
-     *            The buffer into which bytes are to be transferred
+     *            the buffer into which bytes are to be transferred
      *
-     * @return The number of bytes read into {@code dst}, possibly zero, or {@code -1} if the device has reached end-of-stream.
+     * @return the number of bytes read into {@code dst}, possibly zero.
      *
      * @throws NullPointerException
-     *             If {@code dst} is {@code null}.
+     *             if {@code dst} is {@code null}.
      * @throws InvalidWordLengthException
      *             if the number of bytes to receive belies word length.
      * @throws UnavailableDeviceException
@@ -174,7 +184,7 @@
      * @throws ClosedDeviceException
      *             if the device has been closed.
      * @throws IOException
-     *             If some other I/O error occurs
+     *             if some other I/O error occurs.
      */
     @Override
     int read(ByteBuffer dst) throws IOException, UnavailableDeviceException, ClosedDeviceException;
@@ -190,14 +200,14 @@
      * @param skip
      *            the number of read bytes that must be ignored/skipped before filling in the {@code dst} buffer.
      * @param dst
-     *            The buffer into which bytes are to be transferred
+     *            the buffer into which bytes are to be transferred
      *
-     * @return The number of bytes read into {@code dst}, possibly zero, or {@code -1} if the device has reached end-of-stream.
+     * @return The number of bytes read into {@code dst}, possibly zero.
      *
      * @throws NullPointerException
-     *             If {@code dst} is {@code null}.
+     *             if {@code dst} is {@code null}.
      * @throws IllegalArgumentException
-     *              If {@code skip} is negative.
+     *              if {@code skip} is negative.
      * @throws InvalidWordLengthException
      *             if the total number of bytes to receive belies word length.
      * @throws UnavailableDeviceException
@@ -205,37 +215,57 @@
      * @throws ClosedDeviceException
      *             if the device has been closed.
      * @throws IOException
-     *             If some other I/O error occurs
+     *             if some other I/O error occurs.
      */
     int read(int skip, ByteBuffer dst) throws IOException, UnavailableDeviceException, ClosedDeviceException;
 
     /**
      * Writes a sequence of bytes to this slave device from the given buffer.
      * <p />
-     * {@inheritDoc}
+     * An attempt is made to write up to <i>r</i> bytes to the device, where <i>r</i> is the number
+     * of bytes remaining in the buffer, that is, {@code src.remaining()}, at the moment this method
+     * is invoked.
+     * <p />
+     * Suppose that a byte sequence of length <i>n</i> is written, where <i>{@code 0 <= n <= r}</i>.
+     * This byte sequence will be transferred from the buffer starting at index <i>p</i>, where
+     * <i>p</i> is the buffer's position at the moment this method is invoked; the index of the last
+     * byte written will be <i>{@code p + n - 1}</i>. Upon return the buffer's position will be
+     * equal to <i>{@code p + n}</i>; its limit will not have changed.
+     * <p />
+     * A write operation will return only after writing all of the <i>r</i> requested bytes.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a read or write
+     * operation upon this slave device, however, then an invocation of this method will block until
+     * the first operation is complete.
      *
      * @param src
-     *            The buffer from which bytes are to be retrieved
-     * @return The number of bytes written from {@code src}, possibly zero
+     *            the buffer from which bytes are to be retrieved.
+     * @return the number of bytes written from {@code src}, possibly zero.
+     * @throws InvalidWordLengthException
+     *             if the number of bytes to send belies word length.
      * @throws NullPointerException
-     *             If {@code src} is {@code null}.
+     *             if {@code src} is {@code null}.
      * @throws UnavailableDeviceException
      *             if this device is not currently available - such as it is locked by another application.
      * @throws ClosedDeviceException
      *             if the device has been closed.
      * @throws IOException
-     *             If some other I/O error occurs
+     *             if some other I/O error occurs.
      */
     @Override
     int write(ByteBuffer src) throws IOException, UnavailableDeviceException, ClosedDeviceException;
 
     /**
      * Writes one data word of up to 32 bits to this slave device.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a read or write
+     * operation upon this slave device, however, then an invocation of this method will block until
+     * the first operation is complete.
      *
      * @param txData
-     *            the data word to be written
+     *            the data word to be written.
      * @throws IOException
-     *             if an I/O error occurred
+     *             if an I/O error occurred.
      * @throws InvalidWordLengthException
      *             if the number of bytes to send belies word length; that is this slave's word length is bigger than 32
      *             bits.
@@ -257,12 +287,12 @@
      * {@link SPIDevice#read(java.nio.ByteBuffer)}.
      *
      * @param src
-     *            The buffer from which bytes are to be retrieved
+     *            the buffer from which bytes are to be retrieved.
      * @param dst
-     *            The buffer into which bytes are to be transferred
-     * @return The number of bytes read into {@code dst}, possibly zero, or {@code -1} if the device has reached end-of-stream.
+     *            the buffer into which bytes are to be transferred.
+     * @return The number of bytes read into {@code dst}, possibly zero.
      * @throws NullPointerException
-     *             If {@code src} or {@code dst} is {@code null}.
+     *             if {@code src} or {@code dst} is {@code null}.
      * @throws InvalidWordLengthException
      *             if the number of bytes to receive or send belies word length.
      * @throws UnavailableDeviceException
@@ -270,7 +300,7 @@
      * @throws ClosedDeviceException
      *             if the device has been closed.
      * @throws IOException
-     *             If some other I/O error occurs
+     *             if some other I/O error occurs.
      */
     int writeAndRead(ByteBuffer src, ByteBuffer dst) throws IOException, UnavailableDeviceException, ClosedDeviceException;
 
@@ -285,16 +315,16 @@
      * {@link SPIDevice#read(java.nio.ByteBuffer)}.
      *
      * @param src
-     *            The buffer from which bytes are to be retrieved
+     *            the buffer from which bytes are to be retrieved.
      * @param skip
      *            the number of received bytes that must be ignored/skipped before filling in the {@code dst} buffer.
      * @param dst
-     *            The buffer into which bytes are to be transferred
-     * @return The number of bytes read into {@code dst}, possibly zero, or {@code -1} if the device has reached end-of-stream.
+     *            the buffer into which bytes are to be transferred.
+     * @return the number of bytes read into {@code dst}, possibly zero.
      * @throws NullPointerException
-     *             If {@code src} or {@code dst} is {@code null}.
+     *             if {@code src} or {@code dst} is {@code null}.
      * @throws IllegalArgumentException
-     *              If {@code skip} is negative.
+     *              if {@code skip} is negative.
      * @throws InvalidWordLengthException
      *             if the total number of bytes to receive or send belies word length.
      * @throws UnavailableDeviceException
@@ -302,12 +332,16 @@
      * @throws ClosedDeviceException
      *             if the device has been closed.
      * @throws IOException
-     *             If some other I/O error occurs
+     *             if some other I/O error occurs.
      */
     int writeAndRead(ByteBuffer src, int skip, ByteBuffer dst) throws IOException, UnavailableDeviceException, ClosedDeviceException;
 
     /**
      * Exchanges (transmits and receives) one data word of up to 32 bits with this slave device.
+     * <p />
+     * This method may be invoked at any time. If another thread has already initiated a read or write
+     * operation upon this slave device, however, then an invocation of this method will block until
+     * the first operation is complete.
      *
      * @param txData
      *            the word to send.
--- a/src/share/classes/jdk/dio/spibus/SPIDeviceConfig.java	Mon Feb 02 13:46:41 2015 +0400
+++ b/src/share/classes/jdk/dio/spibus/SPIDeviceConfig.java	Mon Feb 02 13:50:33 2015 +0400
@@ -42,7 +42,7 @@
  * <h3><a name="mode">SPI Clock Modes</a></h3>
  * The clock mode is a number from 0 to 3 which represents the combination of the CPOL (SPI Clock Polarity Bit) and CPHA
  * (SPI Clock Phase Bit) signals where CPOL is the high order bit and CPHA is the low order bit:
- * <table style="border:1px solid black;border-collapse:collapse;" * summary="The clock mode is a number which represents the combination of the CPOL (SPI Clock Polarity Bit) * and CPHA (SPI Clock Phase Bit) signals.">
+ * <table style="border:1px solid black;border-collapse:collapse;" summary="The clock mode is a number which represents the combination of the CPOL (SPI Clock Polarity Bit) and CPHA (SPI Clock Phase Bit) signals.">
  * <tr style="border:1px solid black;">
  * <th id="t1" style="border:1px solid black;">Mode</th>
  * <th id="t2" style="border:1px solid black;">CPOL</th>
--- a/src/share/classes/jdk/dio/spibus/package-info.java	Mon Feb 02 13:46:41 2015 +0400
+++ b/src/share/classes/jdk/dio/spibus/package-info.java	Mon Feb 02 13:50:33 2015 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
  * <p />
  * In order to communicate with a specific slave, an application should first open and obtain an
  * {@link jdk.dio.spibus.SPIDevice} instance for the SPI slave device the application wants to exchange
- * data with, using its numeric ID, name, type (interface) or properties:
+ * data with, using its numeric ID, name, type (interface) and/or properties:
  * <dl>
  * <dt>Using its ID</dt>
  * <dd>
@@ -75,14 +75,16 @@
  *    ByteBuffer sndBuf1 = ByteBuffer.wrap(new byte[] {0x01});
  *    ByteBuffer sndBuf2 = ByteBuffer.wrap(new byte[] {0x02});
  *    ByteBuffer rcvBuf = ByteBuffer.wrap(new byte[3]);
+ *    rcvBuf.limit(1);
  *    slave.writeAndRead(sndBuf1, rcvBuf); //received data will be stored in rcvBuf[0]
+ *    rcvBuf.limit(3);
  *    slave.writeAndRead(sndBuf2, rcvBuf); //received data will be stored in rcvBuf[1] and rcvBuf[2]
  * } catch (IOException ioe) {
  *     // handle exception
  * }
  * </pre>
  *
- * </blockquote> The preceding example is using a <em>try-with-resources</em> statement and that the
+ * </blockquote> The preceding example is using a <em>try-with-resources</em> statement; the
  * {@link jdk.dio.spibus.SPIDevice#close SPIDevice.close} method is automatically invoked by the
  * platform at the end of the statement.
  * <p />
--- a/src/share/native/com/oracle/dio/javacall_spi.h	Mon Feb 02 13:46:41 2015 +0400
+++ b/src/share/native/com/oracle/dio/javacall_spi.h	Mon Feb 02 13:50:33 2015 +0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -207,15 +207,17 @@
 
 /**
  * Demarcates the beginning of an SPI transaction, e.g. asserts
- * CS pin and prevent other SPI client to access the bus.
+ * CS pin (where it is possible) and prevent other SPI client to
+ * access the bus.
+ *
+ * @note platforms where CS mangle is unsupported must implement
+ *       logical demarcation only.
  *
  * @param handle for SPI slave
  *
  * @retval JAVACALL_DIO_OK    success
  * @retval JAVACALL_DIO_INVALID_STATE if the bus is already
  *         locked by any device
- * @retval JAVACALL_DIO_UNSUPPORTED_OPERATION arbitrary control
- *         of CS pin is not supported
  * @retval JAVACALL_DIO_FAIL it is impossible to lock the bus
  */
 javacall_dio_result javacall_spi_begin(javacall_handle pHandle);