Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 06 Sep 2002 23:51:10 -0600 (MDT)
From:      "M. Warner Losh" <imp@bsdimp.com>
To:        bms@spc.org
Cc:        freebsd-hackers@FreeBSD.ORG
Subject:   Re: PCMCIA questions: mapping attribute and common memory?
Message-ID:  <20020906.235110.108188889.imp@bsdimp.com>
In-Reply-To: <20020906093215.GI15218@spc.org>
References:  <20020905191546.GF15218@spc.org> <20020905.145936.39157187.imp@bsdimp.com> <20020906093215.GI15218@spc.org>

next in thread | previous in thread | raw e-mail | index | archive | help
In message: <20020906093215.GI15218@spc.org>
            Bruce M Simpson <bms@spc.org> writes:
: Thanks for your informative response.

Sure.  Sorry for the long delay on this one.  I wanted to give a good
answer rather than a fast one.

: On Thu, Sep 05, 2002 at 02:59:36PM -0600, M. Warner Losh wrote:
: > You generally don't map attribute memory.  With one exception (the
: > raylan cards), there's no hardware in the attribute memory section and
: > it is just used to store the cis.
: ...
: [ray(4) and xe(4)]
: > Those are the two worst ones to look at.  Don't do what they do, as
: > the ray(4) hardware is weird and the xe(4) driver was written before
: > we could read the cis from the kernel.
: 
: The particular device I'm working with is the Gemplus GPR400 PCMCIA
: Smart Card Reader. It has hardware registers in the attribute memory.

Yuck!  Fortunately, I've been sensitized to it by the raylink driver.

: One of these registers tells me when a card is inserted/ejected, and
: there are also some bits in that space which are used to handle
: suspending and resuming the card.

ok.

: What's the best way for me to do this, whilst being OLDCARD and NEWCARD
: compatible? (And just out of interest, is it possible to read the CIS
: from the kernel easily whilst still being OLDCARD friendly?)

Do you need to read the CIS directly?  Or do you just need to map the
attribute memory to access well known locationss?  The answer isn't
much different, and I'll get into that below.

: > : If so, how do I get at the resource?
: > : If not, how would I go about doing this myself in the driver?
: > 
: > bus_alloc_resource()
: 
: Ok. Say I have my first two tuples and they look like this:-
: 
: Tuple #1, code = 0x1 (Common memory descriptor), length = 3
:     000:  d4 00 ff
:         Common memory device information:
:                 Device number 1, type Function specific, WPS = OFF
:                 Speed = 100nS, Memory block size = 512b, 1 units
:
: Tuple #2, code = 0x17 (Attribute memory descriptor), length = 3
:     000:  64 10 ff
:         Attribute memory device information:
:                 Device number 1, type SRAM, WPS = OFF
:                 Speed = 100nS, Memory block size = 512b, 3 units
: 
: How will these blocks be mapped when I allocate the resource?

They are memory mapped devices.

: Are they
: coalesced into a single memory map in the order in which they appear in the
: CIS? Thing is, 2KB is 0x800 hex, and the register addresses I see in this
: Linux code I'm porting all start at 0xFA0. This would seem to indicate
: that a 2KB memory window is needed. [(3+1)*512]. The Linux code asks for a
: window size of 0x1000, which is 4KB, yet the comment says it's asking for
: 2KB. Bizarre.

Linux code tends to say one thing and do another often. :-)

: Once I've allocated the window as a resource, how would I go about accessing
: that memory directly? Would I need to establish a page mapping?

OK.  Lemme talk with code (which I've grabbed from ray_res_alloc_am)

	sc->am_rid = RAY_AM_RID;
	sc->am_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY,
	    &sc->am_rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev,
	    sc->am_rid, 0, NULL);
	error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev,
	    SYS_RES_MEMORY, sc->am_rid, PCCARD_A_MEM_ATTR);
	error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev,
	    SYS_RES_MEMORY, sc->am_rid, PCCARD_A_MEM_8BIT);

(I'm not sure why the ray driver doesn't combine the last two calls).

The rid is 3.  pccardd abuses window 0 (and the comments in the
ray driver say 1 also, which may be possible).  We really should use
window 4 for the CIS, but that's too big a change (and would break
support for media chipsets, which have only one memory map, but those
are only on early pc98 laptops).

Anyway, you pick the window that you want to use.  You the map it.  To
manage where in the memory you'd like to map it, you set the offset.
To make it the attribute memory, we set the resoruce flags.  Ditto
with 8 bit.  Allocating the common memory would be similar.

In the ray driver, it uses rid 0 for the common memory so it can get
the size of the memory.  So that code looks like:

	u_long start, count, end;
	sc->cm_rid = RAY_CM_RID;
	start = bus_get_resource_start(sc->dev, SYS_RES_MEMORY, sc->cm_rid);
	count = bus_get_resource_count(sc->dev, SYS_RES_MEMORY, sc->cm_rid);
	end = start + count - 1;
	sc->cm_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY,
	    &sc->cm_rid, start, end, count, RF_ACTIVE);
	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->dev), sc->dev,
	    sc->cm_rid, 0, NULL);
	error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev,
	    SYS_RES_MEMORY, sc->cm_rid, PCCARD_A_MEM_COM);
	error = CARD_SET_RES_FLAGS(device_get_parent(sc->dev), sc->dev,
	    SYS_RES_MEMORY, sc->cm_rid, PCCARD_A_MEM_8BIT);

which is very similar.  This only works because the rid is 0.  I'm not
sure what the CIS of the ray cards look like (my ray cards aren't
easily accessible at the moment).

So if you need to read the CIS, you'll have to find out where in the
attribute memory the CIS lives.  There are ways to do this generically
for pccards, but I don't know if you can do it inside a client
driver.  The -current version uses some of the generic information
passed in from pccardd.  I need to MFC that functionality into
-stable.

: [probe]
: > Ideally, you'd just match the OEM ID and vendor info of the card.
: > Less ideally, you'd match the strings in the CIS.
: 
: So why do many pccard driver probes allocate and deallocate their
: card's resources? Is this merely to make sure they're available in
: anticipation of attach?

That's a legacy of OLDCARD and ISA.  Old-school ISA devices needed to
be querried to make sure they were still there.  Many of these probe
routines bogusly had side effects, either in the hardware or in the
softc of the driver.  So rather than fix them all when we were adding
pccard attachments to these devices, we just made pccard devices do
the same thing as ISA.  NEWCARD encourages folks to just use the IDs
to figure this out.

So how do you make things compatible between NEWCARD and OLDCARD?
Well, they are basically the same.  However, the is a slight
difference.  In OLDCARD, pccardd desided what driver will be used,
probe looks for hardware, and attach connects it.  NEWCARD one is just
supposed to look at the ids, while attach is supposed to ready the
hardware and allocate things.  How can these two models be reconsiled?
With some compat shims.

Let's take a look at how ep does it:

static device_method_t ep_pccard_methods[] = {
	/* Device interface */
	DEVMETHOD(device_probe,		pccard_compat_probe),
	DEVMETHOD(device_attach,	pccard_compat_attach),
	DEVMETHOD(device_detach,	ep_pccard_detach),

	/* Card interface */
	DEVMETHOD(card_compat_match,	ep_pccard_match),
	DEVMETHOD(card_compat_probe,	ep_pccard_probe),
	DEVMETHOD(card_compat_attach,	ep_pccard_attach),

	{ 0, 0 }
};

Notice two things.  First, probe and attach are a generic shim that
calls either the OLDCARD or the NEWCARD routines.  We also provide 3
generic routines.  1 that matches, one that probes and one that
attaches.  The reason I split them up was that OLDCARD's agent of
driver choice is pccardd, while in NEWCARD it is the driver itself.

So, ep_pccard_match looks fairly simple:

static int
ep_pccard_match(device_t dev)
{
	const struct pccard_product *pp;

	if ((pp = pccard_product_lookup(dev, ep_pccard_products,
	    sizeof(ep_pccard_products[0]), NULL)) != NULL) {
		device_set_desc(dev, pp->pp_name);
		return 0;
	}
	return EIO;
}

and most drivers will have some variation on this.  Some drivers have
additional information in their tables and they look things up to find
info specific to that device (which is why we pass the size into the
lookup routine).

The ep_pccard_probe routine then looks for the hardware.  It did this
to provide a reasonable string in the description.  Your driver likely
won't want to do this.  The ep_pccard_attach routine allocates
resources.  Your driver will want to allocate resources here and set
things up.

For OLDCARD, pccard_compat_probe calls ep_pccard_probe, and
pccard_compat_attach calls ep_pccard_attach.  For NEWCARD,
pccard_compat_probe calls ep_pccard_match and pccard_compat_probe
calls ep_pccard_probe and ep_pccard_attach.

Well, that's enough for now.  Any further questions?

Warner

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020906.235110.108188889.imp>