Again, I haven't analyzed the problem in detail, but there seem to be a few things odd about your code. I often find the way to get to the bottom of the problem is to simplify it progressively.
Starting with the template
<xsl:template match="submap" mode="level">
<xsl:variable name="cursub" select="."/>
<xsl:variable name="totgrps" select="//device[generate-id(.)=generate-id(key('kdgroups',grp))]"/>
<xsl:text>
Submap </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text> - </xsl:text>
<xsl:for-each select="$totgrps">
<xsl:variable name="loopgrp" select="grp"/>
<xsl:for-each select="$cursub">
<xsl:if test="count(descendant::device[grp=$loopgrp]) > 0">
<xsl:value-of select="$loopgrp"/>
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
(a) the value of $totgrps doesn't depend on the context node (assuming that the stylesheet only has one input document), so it can be pulled out of the template and turned into a global variable. Its value is all the device elements that are the first in their group.
(b) $cursub is a single node, therefore the expression
<xsl:for-each select="$cursub">
<xsl:if test="count(descendant::device[grp=$loopgrp]) > 0">
<xsl:value-of select="$loopgrp"/>
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
can be replaced by
<xsl:if test="$cursub/descendant::device[grp=$loopgrp]">
<xsl:value-of select="$loopgrp"/>
<xsl:text>,</xsl:text>
</xsl:if>
and this of course means that you don't need the variable $loopgrp, so I think the template reduces to:
<xsl:template match="submap" mode="level">
<xsl:variable name="cursub" select="."/>
<xsl:text>
Submap </xsl:text>
<xsl:value-of select="@name"/>
<xsl:text> - </xsl:text>
<xsl:for-each select="$totgrps">
<xsl:if test="$cursub/descendant::device[grp=current()/grp]">
<xsl:value-of select="grp"/>
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
I think the test on position()=last() will then work: it isn't working at the moment because the innermost xsl:for-each is iterating over a single node, so position() is always equal to last().
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference