<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-11751455</id><updated>2011-04-21T14:03:18.512-07:00</updated><title type='text'>XYZ Interix Development</title><subtitle type='html'>Development log for porting application to Interix.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-11751455.post-111392015377062520</id><published>2005-04-19T07:14:00.000-07:00</published><updated>2005-04-19T07:15:53.783-07:00</updated><title type='text'>Shared library issue in Interix</title><content type='html'>This is extract from &lt;strong&gt;Unix Tool Forum&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.interopsystems.com/tools/forum/tm.aspx?m=1794&amp;amp;mpage=1&amp;key=shared%2clibrary&amp;amp;#1794"&gt;http://www.interopsystems.com/tools/forum/tm.aspx?m=1794&amp;amp;mpage=1&amp;key=shared%2clibrary&amp;amp;#1794&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 15, '04, 1:27:26 AM&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As many of you know Interix 3.5 ships with the several &lt;span class="high"&gt;shared&lt;/span&gt; libraries.&lt;br /&gt;The default when you are linking applications is for the &lt;span class="high"&gt;shared&lt;/span&gt; libraries&lt;br /&gt;to be used. When an image is created information from the &lt;span class="high"&gt;shared&lt;/span&gt; libraries&lt;br /&gt;is used to determine where the memory base (image base) is located.&lt;br /&gt;At run time the image is loaded and they &lt;span class="high"&gt;shared&lt;/span&gt; libraries are loaded as&lt;br /&gt;well. Each &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; has information about where it should have it's&lt;br /&gt;image base should be located as well. When a conflict (image base overlap)&lt;br /&gt;happens you are at the mercy of the loader determining the relocation of&lt;br /&gt;one or more of the &lt;span class="high"&gt;shared&lt;/span&gt; libraries and/or the application.&lt;br /&gt;&lt;br /&gt;When a &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; or application is linked you can specify the image&lt;br /&gt;base for each. For applications linking the default is usually quite good&lt;br /&gt;so there should not be a problem. For applications the default seems to be&lt;br /&gt;0x400000 (yes, we only speak in hexadecimal &lt;img alt="" src="http://www.interopsystems.com/tools/forum/image/s1.gif" align="middle" border="0" /&gt; ).&lt;br /&gt;&lt;br /&gt;When a &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; is linked the default image base is set to 0x10000000.&lt;br /&gt;If this default is accepted and an application uses more than one &lt;span class="high"&gt;shared&lt;/span&gt;&lt;br /&gt;&lt;span class="high"&gt;library&lt;/span&gt; using the default then an image base conflict happens. This results&lt;br /&gt;in relocation. This slows things down a bit at startup. It can also result&lt;br /&gt;in the available memory becoming fragmented so very large memory allocations&lt;br /&gt;cannot happen. It can also result in an application's image base being different&lt;br /&gt;than above which might make thing even more unfavourable.&lt;br /&gt;&lt;br /&gt;The image base for each of the &lt;span class="high"&gt;shared&lt;/span&gt; libraries shipped with Interix 3.5 has a&lt;br /&gt;specific image base set that does not conflict with any other &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt;&lt;br /&gt;shipped. The spacing between them is more than enough. A rough way of stating it&lt;br /&gt;is that the next higher image base must account for size of the object at this&lt;br /&gt;image base (no overlaps).&lt;br /&gt;&lt;br /&gt;To this date I've released the various additional libraries without specify an&lt;br /&gt;image base. To date this hasn't been a problem. As you may guess I finally found&lt;br /&gt;it to be a problem. It took some time finding this out. I'm not looking to get&lt;br /&gt;bit by this again nor do I wish anyone else to get bit by it.&lt;br /&gt;&lt;br /&gt;In most circumstances the current status won't be a problem for anyone.&lt;br /&gt;I ran into the problem while working on a release of &lt;b&gt;OpenDX&lt;/b&gt; for Interix.&lt;br /&gt;You can refer to &lt;a href="http://www.opendx.org" target="_blank"&gt;http://www.opendx.org&lt;/a&gt; for more info on &lt;b&gt;OpenDX&lt;/b&gt; for now.&lt;br /&gt;You can do some wicked-cool 2-D and 3-D graphics with it.&lt;br /&gt;Anyway, it loads many &lt;span class="high"&gt;shared&lt;/span&gt; libraries and is itself a large image (0x731000 bytes).&lt;br /&gt;I noticed my problem when an sbrk() wasn't working for more than 0x10000 bytes.&lt;br /&gt;Give rlimit was indicating I had gobs of room it didn't become clear until I mapped&lt;br /&gt;out everything im memory and found that this had been relocated a fair bit causing&lt;br /&gt;the memory (for sbrk()) to be squeezed down to almost nothing. Once I build the&lt;br /&gt;couple of /Tools &lt;span class="high"&gt;shared&lt;/span&gt; libraries with a specific image base then things worked&lt;br /&gt;fine. I still have other work to do with &lt;b&gt;OpenDX&lt;/b&gt; but this hurtle is over.&lt;br /&gt;&lt;br /&gt;ANYWAY! This has been a long-winded explanation about my starting a registry list&lt;br /&gt;for &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; image bases. I have all of the images bases mapped out for what&lt;br /&gt;ships with 3.5. That gives a "zone" that we'll leave alone for the SFU dev folks.&lt;br /&gt;For the /Tools &lt;span class="high"&gt;shared&lt;/span&gt; libraries I'm going to go through them and assign image bases.&lt;br /&gt;All of this I'm going to place in a list on the ftp-site that people can read.&lt;br /&gt;If you are wanting to set an image base for a &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; that you are going to&lt;br /&gt;make public this file will help you pick a "conflict free zone". This way we can&lt;br /&gt;all work together in harmony &lt;img alt="" src="http://www.interopsystems.com/tools/forum/image/s1.gif" align="middle" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;To specify an image base with &lt;b&gt;ld&lt;/b&gt; the option (not on the man page BTW) is:&lt;br /&gt;&lt;pre&gt;    --image-base &amp;lt;value&amp;gt;&lt;/pre&gt;&lt;br /&gt;where it's best to specify &amp;lt;value&amp;gt; in hexadecimal.&lt;br /&gt;For &lt;b&gt;gcc&lt;/b&gt; to pass it along specify it as:&lt;br /&gt;&lt;pre&gt;    -Wl,--image-base,&amp;lt;value&amp;gt;&lt;/pre&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 17, '04, 12:44:31 AM&lt;/span&gt;&lt;/strong&gt;   &lt;br /&gt;&lt;br /&gt;The file in it's current state is located at &lt;a href="ftp://ftp.interopsystems.com/pub/lib_bases" target="_blank"&gt;ftp://ftp.interopsystems.com/pub/lib_bases&lt;/a&gt;&lt;br /&gt;and I'll update it as I make changes to /Tools and as people let me know their info.&lt;br /&gt;&lt;br /&gt;People are welcome to comment and add suggestions on this.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is a follow-up to my previous message.&lt;br /&gt;I've updated a number of packages that contain libraries by changing&lt;br /&gt;them so that each &lt;span class="high"&gt;library&lt;/span&gt; has an image base. I've updated the file&lt;br /&gt;listing the image bases to reflect what I've set so far. Thanks to&lt;br /&gt;Mark for confirming/adding to the list.&lt;br /&gt;&lt;br /&gt;The ones done so far (with their updated version numbers) are:&lt;br /&gt;&lt;pre&gt;glib-2.4.0.2-bin.tgz&lt;br /&gt;libiconv-1.9.2.1-bin.tgz&lt;br /&gt;libcrypt-1.2.1-bin.tgz&lt;br /&gt;libpng-1.2.5.3-bin.tgz&lt;br /&gt;jpeg-6b.3-bin.tgz&lt;br /&gt;libfreetype-2.1.4.3-bin.tgz&lt;br /&gt;xrender-0.8.2.3-bin.tgz&lt;br /&gt;zlib-1.1.4e-bin.tgz&lt;br /&gt;xft-2.1.2.4-bin.tgz&lt;br /&gt;libxpm-3.4k.3-bin.tgz&lt;br /&gt;tiff-3.5.7.4-bin.tg&lt;/pre&gt;&lt;br /&gt;Each of these packages contains at least one, two, three of four libraries.&lt;br /&gt;This makes about half the libraries packaged "based". So sometime next week&lt;br /&gt;should see this done (probably the latter half looking at my schedule).&lt;br /&gt;&lt;br /&gt;For those wondering: &lt;b&gt;OpenDX&lt;/b&gt; seems to be working. I need to work out&lt;br /&gt;some configuration things with it before it will be released.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 20, '04, 5:55:58 PM&lt;/span&gt;&lt;/strong&gt;   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This looks like you're saying that "-fPIC" is not creating a procedure linkage table (PLT) or global offset table (GOT). Is this true?&lt;br /&gt;&lt;br /&gt;Most *ix systems don't need an image base for &lt;span class="high"&gt;shared&lt;/span&gt; objects precisely because of the presence of the above two tables. The dynamic linker (ld.so, or whatever it may be called) is supposed to take care of the situation by filling in the GOT and PLT as needed.&lt;br /&gt;&lt;br /&gt;I'm not running into this problem (yet), but I'm definitely curious as to how this ends up "fragmenting" memory. Most ld.so implementations use mmap and end up mapping a memory region far beyond where sbrk() might go. Is 0x10000000 too close to sbrk()'s boundary? Perhaps this should be changed in the bfd/binutils glue to something higher in memory.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 20, '04, 7:36:32 PM&lt;/span&gt;&lt;/strong&gt;    &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;The port of &lt;b&gt;gcc&lt;/b&gt; was not finished for PIC.&lt;br /&gt;So using PIC will sometimes, not all times, send code into never-never&lt;br /&gt;land once it's run.&lt;br /&gt;Because of the way the NT loader does things you can specify the image-base.&lt;br /&gt;The 0x100000000 default location is pretty low for large applications.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 21, '04, 12:04:01 AM&lt;/span&gt;&lt;/strong&gt;    &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;Hm. No PIC? That's pretty close to a showstopper. Is PIC support still being worked on, or is it now abandoned?&lt;br /&gt;&lt;br /&gt;Further, is it possible to use the off-the-shelf binutils if it is assumed that PIC still doesn't work? The beta-snapshot "2.13.90" shipped with SFU 3.5 has some issues, and it would be nice to use 2.14.&lt;br /&gt;&lt;br /&gt;In that case, I guess I'll try something rather off-the-wall to support shlibs in pkgsrc and libtool under Interix 3.[015] with some degree of efficiency: an image base between, say, 0x40000000 and 0x80000000, choosing a random bitset for the 0x3FFC0000 bitmask with 12 bits of randomness. That gives a N/4096 random chance of overlap occurring (where N is the number of shlibs loaded &amp;lt;= 4MB, more if some are &amp;gt; 4MB), without having to use a registry -- something useless for automated shlib building.&lt;br /&gt;&lt;br /&gt;Off to try out this hack of a kludge of a workaround of a patch....&lt;br /&gt;&lt;br /&gt;In addition, I plan to submit a patch to the gcc maintainers to make -fpic/-fPIC a no-op for Interix unless you say that PIC is still under development. It shouldn't be possible to have these options do something that looks useful if it's actually harmful.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 21, '04, 12:57:39 AM&lt;/span&gt;&lt;/strong&gt;    &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&amp;gt; Hm. No PIC? That's pretty close to a showstopper. Is PIC support still being worked on,&lt;br /&gt;&amp;gt; or is it now abandoned?&lt;br /&gt;&lt;br /&gt;It stopped. The brief history is the work started when OpenNT/Interix was&lt;br /&gt;by Softway Systems (Mark, Bill and I were there). After MS bought Interix&lt;br /&gt;the work continued (MS hired the guy doing the gcc/ld work). That allowed&lt;br /&gt;for the work to be updated to gcc 3.X. Additional work was done beyond&lt;br /&gt;what was done for gcc 2.X. MS doesn't prefer people staying with a project&lt;br /&gt;too long (it's their style). So he had to move on. That's when it stopped.&lt;br /&gt;I think between then and the 3.5 release someone adjusted some minor things.&lt;br /&gt;I asked about PIC (and some other stuff) getting done several times, but it&lt;br /&gt;didn't happen.&lt;br /&gt;&lt;br /&gt;&amp;gt; Further, is it possible to use the off-the-shelf binutils if it is assumed&lt;br /&gt;&amp;gt; that PIC still doesn't work? The beta-snapshot "2.13.90" shipped with SFU&lt;br /&gt;&amp;gt; 3.5 has some issues, and it would be nice to use 2.14.&lt;br /&gt;&lt;br /&gt;There are changes to binutils. So you'd want to copy the changes ahead.&lt;br /&gt;But I don't see this being a problem. (Time consuming, but not a problem).&lt;br /&gt;&lt;br /&gt;&amp;gt; In that case, I guess I'll try something rather off-the-wall to support shlibs in pkgsrc and libtool&lt;br /&gt;&amp;gt;under Interix 3.[015] with some degree of efficiency: an image base between, say, 0x40000000 and&lt;br /&gt;&amp;gt;0x80000000, choosing a random bitset for the 0x3FFC0000 bitmask with 12 bits of randomness. That gives a&lt;br /&gt;&amp;gt;N/4096 random chance of overlap occurring (where N is the number of shlibs loaded &amp;lt;= 4MB, more if some&lt;br /&gt;&amp;gt;are &amp;gt; 4MB), without having to use a registry -- something useless for automated shlib building.&lt;br /&gt;&lt;br /&gt;I think I'll pass on this plan.&lt;br /&gt;&lt;br /&gt;&amp;gt; In addition, I plan to submit a patch to the gcc maintainers to make -fpic/-fPIC a no-op for Interix&lt;br /&gt;&amp;gt; unless you say that PIC is still under development. It shouldn't be possible to have these options do&lt;br /&gt;&amp;gt; something that looks useful if it's actually harmful.&lt;br /&gt;&lt;br /&gt;I'll agree on the do-no-harm part.&lt;br /&gt;A couple/several years ago there was a company (I forget the name right now; one of the&lt;br /&gt;ones that does gcc work) that was tasked to get the Interix changes merged in with the&lt;br /&gt;gcc mainline of code. For reasons I don't know of, it never happened. Turning pic/PIC&lt;br /&gt;off for Interix in the mainline isn't going to do a lot given the other changes aren't&lt;br /&gt;there. I'll see if I can dig up who was supposed to be getting the changes done.&lt;br /&gt;That might be useful to "really fixing" things. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 21, '04, 1:02:59 AM&lt;/span&gt;&lt;/strong&gt;    &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;The gcc3.3 port to Interix was done probably 18-20 months ago.&lt;br /&gt;There were attempts to submit the patches back to who-ever maintains gcc but I have no idea how successful that was.&lt;br /&gt;I do not believe anyone is working on gcc for Interix anymore.&lt;br /&gt;&lt;br /&gt;The source code for the gcc3.3 port to Interix is on the SFU 3.5 distribution media. (CD/sources/Interix/gnu/...)&lt;br /&gt;In case you were interested :-) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;strong&gt;RE: registering shared library image-base - &lt;span class="ultrasmall"&gt;Apr. 21, '04, 1:32:24 AM&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;span class="ultrasmall"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="info"&gt;&lt;span class="ultrasmall"&gt;&lt;br /&gt;&lt;blockquote class="quote"&gt;&lt;i&gt;quote:&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;ORIGINAL: Rodney&lt;br /&gt;&lt;br /&gt;&amp;gt; In that case, I guess I'll try something rather off-the-wall to support shlibs in pkgsrc and libtool&lt;br /&gt;&amp;gt;under Interix 3.[015] with some degree of efficiency: an image base between, say, 0x40000000 and&lt;br /&gt;&amp;gt;0x80000000, choosing a random bitset for the 0x3FFC0000 bitmask with 12 bits of randomness.&lt;br /&gt;&lt;br /&gt;I think I'll pass on this plan.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Well, I don't see much choice on my side in absence of PIC. A registry simply will not work for automated &lt;span class="high"&gt;shared&lt;/span&gt; &lt;span class="high"&gt;library&lt;/span&gt; building via libtool and/or pkgsrc. We're talking about quite literally thousands of shlibs under pkgsrc that I plan to get running, and maintaining an Interix-specific base address registry for them is not going to happen. &lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111392015377062520?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111392015377062520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111392015377062520' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111392015377062520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111392015377062520'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/04/shared-library-issue-in-interix.html' title='Shared library issue in Interix'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111323539629036809</id><published>2005-04-11T08:43:00.000-07:00</published><updated>2005-04-11T09:03:16.290-07:00</updated><title type='text'>How to create a Interix package ?</title><content type='html'>&lt;ol&gt;&lt;li&gt;Download the original source code&lt;/li&gt;&lt;li&gt;Create a temp directory at /var/tmp/port-name&lt;/li&gt;&lt;li&gt;# ./configure --prefix=/var/tmp/port-name&lt;/li&gt;&lt;li&gt;# make; make install&lt;/li&gt;&lt;li&gt;# (cd /var/tmp/port-name &amp;&amp;amp; find -d * \! -type d)  sort &gt; pkgmanifest&lt;/li&gt;&lt;li&gt;Copy packing directory to the /var/tmp/port-name&lt;/li&gt;&lt;li&gt;Edit related files&lt;/li&gt;&lt;li&gt;Run ./pack&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111323539629036809?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111323539629036809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111323539629036809' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323539629036809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323539629036809'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/04/how-to-create-interix-package.html' title='How to create a Interix package ?'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111323244520595197</id><published>2005-04-11T08:11:00.000-07:00</published><updated>2005-04-11T08:14:05.206-07:00</updated><title type='text'>Compile gnu tar-1.15.1</title><content type='html'>&lt;ol&gt;&lt;li&gt;Download sysexits.h to /usr/include from FreeBSD&lt;/li&gt;&lt;li&gt;in the file "src/list.c" adding the conditional:&lt;br /&gt;#ifdef __INTERIX&lt;br /&gt;#define makedev(x,y) mkdev((x), (y))&lt;br /&gt;#endif /* __INTERIX */&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111323244520595197?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111323244520595197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111323244520595197' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323244520595197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323244520595197'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/04/compile-gnu-tar-1151.html' title='Compile gnu tar-1.15.1'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111323195764828042</id><published>2005-04-11T08:04:00.000-07:00</published><updated>2005-04-11T08:05:57.650-07:00</updated><title type='text'>Interix system patch</title><content type='html'>&lt;strong&gt;The things need to be added:&lt;/strong&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;sysexits.h is missing. Download from FreeBSD&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111323195764828042?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111323195764828042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111323195764828042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323195764828042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111323195764828042'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/04/interix-system-patch.html' title='Interix system patch'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111206522552968704</id><published>2005-03-28T19:00:00.000-08:00</published><updated>2005-03-29T17:33:07.266-08:00</updated><title type='text'>WinCE &amp; Linux Blogs</title><content type='html'>&lt;ol&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/mikehall/archive/2004/08/18/216601.aspx"&gt;ESDEVCON - Day 2 - Linux Real Time.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mobilesoft.com.cn/"&gt;http://www.mobilesoft.com.cn/&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111206522552968704?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111206522552968704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111206522552968704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111206522552968704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111206522552968704'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/wince-linux-blogs.html' title='WinCE &amp; Linux Blogs'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111205858317203270</id><published>2005-03-28T17:09:00.000-08:00</published><updated>2005-03-28T17:15:52.956-08:00</updated><title type='text'>Linux SPI architecture</title><content type='html'>&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.katix.org/"&gt;http://www.katix.org/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a onmousedown="return clk(this,'res',7)" href="http://www.katix.org/spi003.pdf"&gt;Katix Embedded Linux SPI Subsystem description&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111205858317203270?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111205858317203270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111205858317203270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111205858317203270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111205858317203270'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/linux-spi-architecture.html' title='Linux SPI architecture'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111202425779940180</id><published>2005-03-28T07:37:00.000-08:00</published><updated>2005-03-28T07:37:37.826-08:00</updated><title type='text'>Driving Me Nuts - Device Classes</title><content type='html'>&lt;h1 class="title"&gt;Driving Me Nuts - Device Classes&lt;/h1&gt;&lt;!-- begin content --&gt;&lt;br /&gt;&lt;div class="node "&gt;&lt;span class="submitted"&gt;&lt;span style="font-size:85%;color:#999999;"&gt;By &lt;/span&gt;&lt;a title="View user profile." href="user/800887"&gt;&lt;strong&gt;&lt;span style="font-size:85%;color:#000000;"&gt;Greg Kroah-Hartman&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;span style="font-size:85%;color:#999999;"&gt; on Thu, 2003-07-31 23:00.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="content"&gt;&lt;br /&gt;&lt;p style="COLOR: red"&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;More necessary instructions for making your new device driver play nice in the 2.6 kernel.&lt;/p&gt;&lt;br /&gt;&lt;div class="article" lang="en"&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573958"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the last Driving Me Nuts column [see &lt;span class="emphasis"&gt;&lt;em&gt;LJ&lt;/em&gt;&lt;/span&gt;, June 2003], we introduced the kernel driver model framework with an explanation of how the generic bus and driver and device code works. The i2c core was used as an example to show how these different subsystems work. This month, we cover how the driver class code works, again using the i2c code to provide some working examples.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As discussed in the last column, device classes do not meet the general object-oriented definition of a class; rather they are something that provides a single type of function to the user. For example, kernel classes are used for tty devices, block devices, network devices, SCSI hosts and, in the near future, filesystems.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the 2.5.69 kernel, the driver class support was rewritten radically. In previous kernel versions, class support was tied tightly to the driver and device support. A class would be bound to the device at the same time it was registered to a driver. This did work for a number of devices and classes, but some real-world devices did not fit very well into this model. Now, class support is tied only loosely to devices and drivers; in fact, a device or driver is not even needed to use the class code now, as the tty class code shows. The class code is now split into three different types of structures: classes, class devices and class interfaces.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573a60"&gt;&lt;/a&gt;Classes&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Classes in the kernel are defined with a simple struct class structure. Yes, class is not a reserved word in C. (Everyone who wants to build a kernel with a C++ compiler, go flame the author of the new class code.) To create a class structure, only the name variable in the struct class structure needs to be defined for it to be a valid class. This can be done with the following code:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static struct class i2c_adapter_class = {&lt;br /&gt;        .name = "i2c_adapter"&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573b10"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;After the class structure is defined, it can be registered with the driver core by calling the class_register function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;if (class_register(&amp;i2c_adapter_class) != 0)&lt;br /&gt;    printk(KERN_ERR "i2c adapter class failed "&lt;br /&gt;                    "to register properly\n");&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573bc0"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;After the class_register function returns without reporting an error, the /sys/class/i2c_adapter directory has been created successfully. Later, when the class needs to be unloaded, the class_unregister function should be called:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;class_unregister(&amp;i2c_adapter_class);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573c70"&gt;&lt;/a&gt;Class Devices&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Classes are used to manage a set of different class devices. A class device is defined in the kernel with the struct class_device structure. This structure contains of a lot of variables the driver core uses, and it can be ignored by the driver writer. Only the following variables should be set:&lt;/p&gt;&lt;br /&gt;&lt;div class="itemizedlist"&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;class: should point to the struct class that is going to manage the class device.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;dev: should be set to the address of the struct device associated with the class device, if any. A single struct device can be pointed to by multiple class device structures. This is the main difference between the previous kernel class support and the current implementation. This variable does not have to be set for the kernel to work properly. If it is set, a device symbolic link is created in the sysfs entry for the class device that points to the struct device. See below for an example.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;class_id: an array of characters used to describe the class device. It must be unique among all class device structures assigned to a single class structure.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;class_data: used to store a pointer to any private data the class driver wants to associate with the class device. This variable should not be accessed directly, but the class_set_devdata and class_get_devdata functions should be used to set and retrieve the value of this variable.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To register a properly set up struct class_device structure, the class_device_register function should be called. An example of how to initialize a struct class_device and register it with the driver core can be seen in the following code from the drivers/i2c/i2c-core.c file:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;/* Add this adapter to the i2c_adapter class */&lt;br /&gt;memset(&amp;adap-&amp;gt;class_dev, 0x00,&lt;br /&gt;       sizeof(struct class_device));&lt;br /&gt;adap-&amp;gt;class_dev.dev = &amp;adap-&amp;gt;dev;&lt;br /&gt;adap-&amp;gt;class_dev.class = &amp;i2c_adapter_class;&lt;br /&gt;strncpy(adap-&amp;gt;class_dev.class_id,&lt;br /&gt;        adap-&amp;gt;dev.bus_id, BUS_ID_SIZE);&lt;br /&gt;class_device_register(&amp;adap-&amp;gt;class_dev);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573ed8"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;First, the struct class_device variable (embedded in the struct i2c_adapter variable) is initialized to zero. All driver model structures need to have all variables set to zero before they are registered, in order for the driver core to use them properly.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Then the dev variable is set to point to the i2c_adapter's struct device variable; in this case, the same structure, struct i2c_adapter, contains both a struct device and a struct class_device. The class variable is set to the address of the i2c_adapter_class variable, and then the class_id variable is set to the same value as the device's bus_id. Because the i2c_adapter device's bus_id is unique, it also ensures that the i2c_adapter class_device's class_id is unique. Finally, the class device structure is registered with the kernel driver core by a call to the class_device_register function.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;With the above code and two i2c adapters loaded on a test machine, the /sys/class/i2c_adapter tree might look like the following: &lt;span class="c3"&gt;Garrick use a smaller font here so the lines won't have to be broken.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ tree /sys/class/i2c-adapter/&lt;br /&gt;/sys/class/i2c-adapter/        &lt;br /&gt;-- i2c-0                      &lt;br /&gt;   -- device -&amp;gt; ../../../devices/pci0/00:07.3/i2c-0&lt;br /&gt;   `-- driver -&amp;gt; ../../../bus/i2c/drivers/i2c_adapter&lt;br /&gt;`-- i2c-2&lt;br /&gt;    -- device -&amp;gt; ../../../devices/legacy/i2c-2&lt;br /&gt;    `-- driver -&amp;gt; ../../../bus/i2c/drivers/i2c_adapter&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As you can see by the above tree output, a device and driver symbolic link are created automatically by the driver core to point to the proper place within the sysfs tree that represents those values. If the dev pointer was not set to point to a struct device, those symbolic links would not have been created. If you look in the /sys/class/tty directory, the majority of those class device entries do not have a corresponding struct device, so those symbolic links are not present.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574038"&gt;&lt;/a&gt;Class Interfaces&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Class interfaces simply are a way for your code to be notified whenever a struct class_device is registered or unregistered from a specific class. A class interface is defined with the struct class_interface structure. This structure is simple and looks like:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;struct class_interface {&lt;br /&gt;    struct list_head  node;&lt;br /&gt;    struct class      *class;&lt;br /&gt;    int (*add)        (struct class_device *);&lt;br /&gt;    void (*remove)    (struct class_device *);&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85740e8"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The class variable needs to be set to the class about which we want to be notified. The add and remove variables should be set to a function that is called when any devices are added or removed, respectively, from that class. It is not necessary to set both the add and remove variables if you do not want to be notified about one of those events.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To register a class interface with the kernel, the class_interface_register function is called. Likewise, to unregister a class interface, the class_interface_unregister function is called. An example of code that uses class interfaces is the CPU frequency core; this code can be found at kernel/cpufreq.c in the kernel source tree.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574198"&gt;&lt;/a&gt;Creating Files&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;As described above, the i2c-adapter class is useful for easily determining all of the different i2c adapters present in the system and their specific location in the driver tree. But i2c adapters are not directly addressable by a user. To talk to an i2c adapter, an i2c chip driver needs to be loaded, or the i2c-dev driver can be used. The i2c-dev driver provides a character driver interface to all i2c adapters present in the system. Because it is useful to determine exactly which i2c-dev devices are attached to which i2c adapters, a i2c-dev class was created:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static struct class i2c_dev_class = {&lt;br /&gt;    .name       = "i2c-dev"&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574248"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Then, when every i2c adapter is found by the i2c-dev driver, a new i2c class device is added to the driver core. This addition is done in the i2c_add_class_device function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static void&lt;br /&gt;i2c_add_class_device(char *name, int minor,&lt;br /&gt;                     struct i2c_adapter *adap)&lt;br /&gt;{&lt;br /&gt;   struct i2c_dev *i2c_dev;&lt;br /&gt;   int retval;&lt;br /&gt;   i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);&lt;br /&gt;   if (!i2c_dev)&lt;br /&gt;       return;&lt;br /&gt;   memset(i2c_dev, 0x00, sizeof(*i2c_dev));&lt;br /&gt;   if (adap-&amp;gt;dev.parent == &amp;legacy_bus)&lt;br /&gt;       i2c_dev-&amp;gt;class_dev.dev = &amp;adap-&amp;gt;dev;&lt;br /&gt;   else&lt;br /&gt;       i2c_dev-&amp;gt;class_dev.dev = adap-&amp;gt;dev.parent;&lt;br /&gt;   i2c_dev-&amp;gt;class_dev.class = &amp;i2c_dev_class;&lt;br /&gt;   snprintf(i2c_dev-&amp;gt;class_dev.class_id,&lt;br /&gt;            BUS_ID_SIZE, "%s", name);&lt;br /&gt;   retval =&lt;br /&gt;       class_device_register(&amp;i2c_dev-&amp;gt;class_dev);&lt;br /&gt;   if (retval)&lt;br /&gt;       goto error;&lt;br /&gt;   class_device_create_file (&amp;i2c_dev-&amp;gt;class_dev,&lt;br /&gt;                             &amp;class_device_attr_dev);&lt;br /&gt;   i2c_dev-&amp;gt;minor = minor;&lt;br /&gt;   spin_lock(&amp;i2c_dev_list_lock);&lt;br /&gt;   list_add(&amp;i2c_dev-&amp;gt;node, &amp;i2c_dev_list);&lt;br /&gt;   spin_unlock(&amp;i2c_dev_list_lock);&lt;br /&gt;   return;&lt;br /&gt;error:&lt;br /&gt;   kfree(i2c_dev);&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85742f8"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This function looks almost like the i2c_adapter class registration code, with two exceptions. First, the class_dev.dev field is set to be either the adapter's parent device or the adapter's device. This is done because some i2c adapters do not have a real parent in the global kernel device tree, as they live on a bus that has not been converted to the kernel driver model (like ISA) or they do not really live on a bus at all (like some i2c embedded controllers). &lt;u&gt;When an i2c adapter does not have a place in the kernel device tree, it is assigned to the legacy bus.&lt;/u&gt; The legacy bus, located at /sys/devices/legacy, is used for these kinds of devices.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The second thing that is different with this class device is the line:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;class_device_create_file (&amp;i2c_dev-&amp;gt;class_dev, &amp;class_device_attr_dev);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574400"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The class_device_create_file function is used to create a file in the class device's directory. The filename and attributes are defined with the CLASS_DEVICE_ATTR macro as: &lt;span class="c3"&gt;Garrick, please kern the double underscores in the code below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static ssize_t&lt;br /&gt;show_dev(struct class_device *class_dev, char *buf)&lt;br /&gt;{&lt;br /&gt;   struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);&lt;br /&gt;   return sprintf(buf, "%04x\n",&lt;br /&gt;                  MKDEV(I2C_MAJOR, i2c_dev-&amp;gt;minor));&lt;br /&gt;}&lt;br /&gt;static&lt;br /&gt;CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The CLASS_DEVICE_ATTR macro is itself defined as:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;#define CLASS_DEVICE_ATTR(_name,_mode,_show,_store) struct class_device_attribute                       class_device_attr_##_name = {                           .attr  = {.name = __stringify(_name),                         .mode = _mode },                          .show  = _show,                                     .store = _store,                                };&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574534"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The arguments within the CLASS_DEVICE_ATTR macro are:&lt;/p&gt;&lt;br /&gt;&lt;div class="itemizedlist"&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;_name: both the name of the file to be created in sysfs and part of the variable name that describes this whole attribute.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;_mode: the file access mode with which the file is created. Use the standard access macros to specify the proper value.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;_show: points to a function that is called when the file is read from. This function must have the following return value and parameters. This variable does not have to be set if the file is not to be read from.&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;ssize_t&lt;br /&gt;show (struct class_device *class_dev, char *buf);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;_store: points to a function that is called when the file is written to. This function must have the following return value and paramaters. This variable does not have to be set if the file is not to be written to.&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;ssize_t&lt;br /&gt;store (struct device *dev, const char *buf,&lt;br /&gt;       size_t count);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2b54"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Almost all driver model structures have an ATTR() macro that declares a file within the sysfs tree.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In this example, a file named dev is created when the class_device_create_file function is called. This file is created to be read-only by any user. If the file is read from, the show_dev function is called by the driver core. The show_dev function fills in the buffer passed to it with the information it wants to give the user. In this case, the major and minor number for this specific device are passed to the user. All class devices using a major and minor number should have a dev file within their sysfs class device directory.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The class_device_remove_file function can be used to remove any files created by the class_device_create_file function. But it is not necessary to remove manually any file created if the device is about to be removed. When devices are removed from sysfs, all files created in their directories are removed automatically by the sysfs core. So, when the i2c-dev class device is removed from the system, all that is needed is the following:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static void&lt;br /&gt;i2c_remove_class_device(int minor)&lt;br /&gt;{&lt;br /&gt;    struct i2c_dev *i2c_dev = NULL;&lt;br /&gt;    struct list_head *tmp;&lt;br /&gt;    int found = 0;&lt;br /&gt;    spin_lock(&amp;i2c_dev_list_lock);&lt;br /&gt;    list_for_each (tmp, &amp;i2c_dev_list) {&lt;br /&gt;        i2c_dev = list_entry(tmp, struct i2c_dev,&lt;br /&gt;                             node);&lt;br /&gt;        if (i2c_dev-&amp;gt;minor == minor) {&lt;br /&gt;            found = 1;&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    if (found) {&lt;br /&gt;        list_del(&amp;i2c_dev-&amp;gt;node);&lt;br /&gt;        spin_unlock(&amp;i2c_dev_list_lock);&lt;br /&gt;        class_device_unregister(&amp;i2c_dev-&amp;gt;class_dev);&lt;br /&gt;        kfree(i2c_dev);&lt;br /&gt;    } else {&lt;br /&gt;    spin_unlock(&amp;i2c_dev_list_lock);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2c5c"&gt;&lt;/a&gt;What It All Looks Like&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;With the i2c-dev driver and two i2c adapter drivers (the i2c-piix4 and i2c-isa drivers) loaded, the /sys/class/i2c-dev directory might look like the following: &lt;span class="c3"&gt;Garrick, please use a smaller font below so the lines don't need to be broken.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ tree /sys/class/i2c-dev/&lt;br /&gt;/sys/class/i2c-dev/   &lt;br /&gt;-- i2c-0     &lt;br /&gt;   -- dev     &lt;br /&gt;   -- device -&amp;gt; ../../../devices/pci0/00:07.3&lt;br /&gt;   `-- driver -&amp;gt; ../../../bus/pci/drivers/piix4-smbus&lt;br /&gt;`-- i2c-2     &lt;br /&gt;    -- dev     &lt;br /&gt;    -- device -&amp;gt; ../../../devices/legacy/i2c-2&lt;br /&gt;    `-- driver -&amp;gt; ../../../bus/i2c/drivers/i2c_adapter&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2d38"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The dev file in the /sys/class/i2c-dev/i2c-2/ directory would contain the following string:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ cat /sys/class/i2c-dev/i2c-2/dev&lt;br /&gt;5902&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2de8"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;which corresponds to major number 86 and minor number 2, the character major and minor numbers for this specific device.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Also, the /sys/bus/i2c/ directory with a few i2c client drivers loaded looks like: &lt;span class="c3"&gt;Garrick, please use a smaller font below so we don't have to break the lines.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ tree /sys/bus/i2c/&lt;br /&gt;/sys/bus/i2c/&lt;br /&gt;-- devices&lt;br /&gt;   -- 0-0050 -&amp;gt; ../../../devices/pci0/00:07.3/i2c-0/0-0050&lt;br /&gt;   -- 0-0051 -&amp;gt; ../../../devices/pci0/00:07.3/i2c-0/0-0051&lt;br /&gt;   -- 0-0052 -&amp;gt; ../../../devices/pci0/00:07.3/i2c-0/0-0052&lt;br /&gt;   -- 0-0053 -&amp;gt; ../../../devices/pci0/00:07.3/i2c-0/0-0053&lt;br /&gt;   `-- 2-0290 -&amp;gt; ../../../devices/legacy/i2c-2/2-0290&lt;br /&gt;`-- drivers&lt;br /&gt;    -- dev driver&lt;br /&gt;    -- eeprom&lt;br /&gt;       -- 0-0050 -&amp;gt; ../../../../devices/pci0/00:07.3/i2c-0/0-0050&lt;br /&gt;       -- 0-0051 -&amp;gt; ../../../../devices/pci0/00:07.3/i2c-0/0-0051&lt;br /&gt;       -- 0-0052 -&amp;gt; ../../../../devices/pci0/00:07.3/i2c-0/0-0052&lt;br /&gt;       `-- 0-0053 -&amp;gt; ../../../../devices/pci0/00:07.3/i2c-0/0-0053&lt;br /&gt;    -- i2c_adapter&lt;br /&gt;    `-- w83781d&lt;br /&gt;        `-- 2-0290 -&amp;gt; ../../../../devices/legacy/i2c-2/2-0290&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;And, the actual /sys/devices/ directories for the i2c adapters look like:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ tree /sys/devices/pci0/00:07.3&lt;br /&gt;/sys/devices/pci0/00:07.3&lt;br /&gt;-- class&lt;br /&gt;-- device&lt;br /&gt;-- i2c-0&lt;br /&gt;   -- 0-0050&lt;br /&gt;      -- eeprom_00&lt;br /&gt;      -- name&lt;br /&gt;      `-- power&lt;br /&gt;   -- 0-0051&lt;br /&gt;      -- eeprom_00&lt;br /&gt;      -- name&lt;br /&gt;      `-- power&lt;br /&gt;   -- 0-0052&lt;br /&gt;      -- eeprom_00&lt;br /&gt;      -- name&lt;br /&gt;      `-- power&lt;br /&gt;   -- 0-0053&lt;br /&gt;      -- eeprom_00&lt;br /&gt;      -- name&lt;br /&gt;      `-- power&lt;br /&gt;   -- name&lt;br /&gt;   `-- power&lt;br /&gt;-- irq&lt;br /&gt;-- name&lt;br /&gt;-- power&lt;br /&gt;-- resource&lt;br /&gt;-- subsystem_device&lt;br /&gt;-- subsystem_vendor&lt;br /&gt;`-- vendor&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2f48"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;and:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;br /&gt;$ tree /sys/devices/legacy/i2c-2/&lt;br /&gt;/sys/devices/legacy/i2c-2/&lt;br /&gt;-- 2-0290&lt;br /&gt;   -- alarms&lt;br /&gt;   -- beep_enable&lt;br /&gt;   -- beep_mask&lt;br /&gt;   -- fan_div1&lt;br /&gt;   -- fan_div2&lt;br /&gt;   -- fan_div3&lt;br /&gt;   -- fan_input1&lt;br /&gt;   -- fan_input2&lt;br /&gt;   -- fan_input3&lt;br /&gt;   -- fan_min1&lt;br /&gt;   -- fan_min2&lt;br /&gt;   -- fan_min3&lt;br /&gt;   -- in_input0&lt;br /&gt;   -- in_input1&lt;br /&gt;   -- in_input2&lt;br /&gt;   -- in_input3&lt;br /&gt;   -- in_input4&lt;br /&gt;   -- in_input5&lt;br /&gt;   -- in_input6&lt;br /&gt;   -- in_input7&lt;br /&gt;   -- in_input8&lt;br /&gt;   -- in_max0&lt;br /&gt;   -- in_max1&lt;br /&gt;   -- in_max2&lt;br /&gt;   -- in_max3&lt;br /&gt;   -- in_max4&lt;br /&gt;   -- in_max5&lt;br /&gt;   -- in_max6&lt;br /&gt;   -- in_max7&lt;br /&gt;   -- in_max8&lt;br /&gt;   -- in_min0&lt;br /&gt;   -- in_min1&lt;br /&gt;   -- in_min2&lt;br /&gt;   -- in_min3&lt;br /&gt;   -- in_min4&lt;br /&gt;   -- in_min5&lt;br /&gt;   -- in_min6&lt;br /&gt;   -- in_min7&lt;br /&gt;   -- in_min8&lt;br /&gt;   -- name&lt;br /&gt;   -- power&lt;br /&gt;   -- pwm1&lt;br /&gt;   -- pwm2&lt;br /&gt;   -- pwm_enable2&lt;br /&gt;   -- sensor1&lt;br /&gt;   -- sensor2&lt;br /&gt;   -- sensor3&lt;br /&gt;   -- temp_input1&lt;br /&gt;   -- temp_input2&lt;br /&gt;   -- temp_input3&lt;br /&gt;   -- temp_max1&lt;br /&gt;   -- temp_max2&lt;br /&gt;   -- temp_max3&lt;br /&gt;   -- temp_min1&lt;br /&gt;   -- temp_min2&lt;br /&gt;   -- temp_min3&lt;br /&gt;   -- vid&lt;br /&gt;   `-- vrm&lt;br /&gt;-- name&lt;br /&gt;`-- power&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;I think the best description of the kernel driver model's use of interconnected structure pointers and representation to the user was issued by Jonathan Corbet: "web woven by a spider on drugs" (&lt;a href="http://lwn.net/Articles/31185/" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;lwn.net/Articles/31185/&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;). Hopefully, these two articles have helped you unravel the loony web, showing the true interconnectedness of all devices within the kernel.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d307c"&gt;&lt;/a&gt;Acknowledgements&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;I would like to thank Pat Mochel for creating such a powerful and complete framework in which all kernel drivers and devices easily can be shown to the user. Also, a big thanks to all of the kernel driver subsystem maintainers who have gladly converted their subsystems over to this model; without their help, the driver core code would have been little more than a nice academic exercise. &lt;span class="c3"&gt;Garrick, please insert the embedded slug.&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Greg Kroah-Hartman is currently the Linux USB and PCI Hot Plug kernel maintainer. He works for IBM, doing various Linux kernel-related things and can be reached at &lt;a href="mailto:greg@kroah.com"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;greg@kroah.com&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;. &lt;span class="c3"&gt;6872aa.tif&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111202425779940180?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111202425779940180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111202425779940180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202425779940180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202425779940180'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/driving-me-nuts-device-classes.html' title='Driving Me Nuts - Device Classes'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111202413982274874</id><published>2005-03-28T07:34:00.000-08:00</published><updated>2005-03-28T07:35:39.840-08:00</updated><title type='text'>The Driver Model Core, Part I</title><content type='html'>&lt;h1 class="title"&gt;The Driver Model Core, Part I&lt;/h1&gt;&lt;!-- begin content --&gt;&lt;br /&gt;&lt;div class="node "&gt;&lt;span class="submitted"&gt;&lt;span style="font-size:85%;color:#999999;"&gt;By &lt;/span&gt;&lt;a title="View user profile." href="user/800887"&gt;&lt;strong&gt;&lt;span style="font-size:85%;color:#000000;"&gt;Greg Kroah-Hartman&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;span style="font-size:85%;color:#999999;"&gt; on Sat, 2003-05-31 23:00.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="content"&gt;&lt;br /&gt;&lt;p style="COLOR: red"&gt;&lt;/p&gt;The 2.5 kernel implements a unified device driver model that will make driver development for 2.6 easier.&lt;br /&gt;&lt;div class="article" lang="en"&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573b04"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the 2.5 Linux kernel development series, a unified device driver model framework was created by Pat Mochel. This framework consists of a number of common structures and functions all device driver subsystems have been converted to use. It also consists of some generic structures that are starting to be used outside of the driver code by other parts of the kernel. This article discusses parts of the driver model and provides an example of how to convert a specific device driver subsystem to the driver model.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573b88"&gt;&lt;/a&gt;Buses, Devices and Classes&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The driver framework breaks all things down into buses, devices and classes. Using these primitives, it controls how drivers are matched up with physical and virtual devices, and it shows the user how all of these things are interconnected.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A bus can be described as something with devices connected to it. Examples of buses are PCI, USB, i2c, PCMCIA and SCSI. Usually only one bus driver controls the activity on a bus, and it provides a type of bridge from the bus it is on to the bus it controls.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;An example of a bridge is a USB controller that lives on the PCI bus. It talks to the PCI bus as a PCI device and looks to the kernel as a PCI driver. But it controls all access to that specific USB bus, talking to the different USB devices plugged in to it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Buses are represented in the kernel with the struct bus_type definition, found in include/linux/device.h. All buses in the system are shown to the user in subdirectories of the sysfs directory /sys/bus/.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="/articles/lj/0110/6717/6717s1.html" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;Sidebar: Sysfs&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Devices are physical or virtual devices that reside on a bus. They are represented by the struct device definition and are created by the bus when the bus sees they are present in the system. Usually only one driver controls a specific device at one time. They can be seen in the /sys/devices directory as a giant tree of all devices in the system or in the /sys/bus/&lt;span class="emphasis"&gt;&lt;em&gt;BUS_TYPE&lt;/em&gt;&lt;/span&gt;/devices/ directory for a specific type of device.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Devices also have drivers assigned to them that control how to talk to the device across a specific bus. Some drivers know how to talk to multiple buses, such as the Tulip network driver, which can talk to PCI and ISA Tulip devices. All drivers are represented by the struct device_driver definition. They can be seen in sysfs at /sys/bus/&lt;span class="emphasis"&gt;&lt;em&gt;BUS_TYPE&lt;/em&gt;&lt;/span&gt;/drivers/. Drivers register with a specific bus and export a list of different types of devices they can support. The bus matches the devices and drivers based on this list of exported devices. The list also is exported to user space so the /sbin/hotplug tools can be used to match drivers to devices that do not have drivers already loaded. See my article, ``Hot Plug'', in the April 2002 issue of &lt;span class="emphasis"&gt;&lt;em&gt;Linux Journal&lt;/em&gt;&lt;/span&gt; for more information on this interface and how it works [also available at &lt;a href="/article/5604" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;www.linuxjournal.com/article/5604&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;].&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Classes here do not take the general object-oriented definition but, rather, are things that provide a function to the user. They are not bus- or device-specific things but functionally look to the user as the same type of device. Examples of classes are audio devices; pointing devices, such as mice and touchpads; keyboards; joysticks; IDE disks; and tty devices. The kernel always has had these kinds of devices, and they traditionally have been grouped together by major/minor number range, so the user can access them easily. Classes are represented in the kernel with the struct device_class definition, and they can be seen as subdirectories of the sysfs directory /sys/class/.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For a description of the whole driver model, along with an introduction to the structures below the driver model that do all of the real work, see the thorough document at &lt;a href="http://www.kernel.org/pub/linux/kernel/people/mochel/doc/lca/driver-model-lca2003.tar.gz" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;www.kernel.org/pub/linux/kernel/people/mochel/doc/lca/driver-model-lca2003.tar.gz&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;. It was written by Pat Mochel for the 2003 Linux.Conf.Au conference.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573e74"&gt;&lt;/a&gt;Theory in Action&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;All of the above descriptions sound great on paper, but how does the driver model actually affect the kernel code? To show this, let us walk through how the i2c driver subsystem was modified to support this driver model.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The i2c code has lived outside of the main kernel tree for a long time, and it was offered as a patch for the 2.0, 2.2 and 2.4 kernels. It also was the subject of ``Using the i2c Bus'', by Simon G. Vogl, one of the main authors of the code [&lt;span class="emphasis"&gt;&lt;em&gt;LJ&lt;/em&gt;&lt;/span&gt;, March 1997, &lt;a href="/article/1342" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;www.linuxjournal.com/article/1342&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;]. In the 2.4 development cycle, a number of the i2c core files and a few i2c bus drivers were accepted into the main kernel. In the 2.5 development cycle, a few more drivers were added; hopefully, all of them eventually will migrate into the main tree. For a good description of the i2c code, what devices it supports and how to use it, see the main development site at &lt;a href="http://secure.netroedge.com/~lm78/index.html" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;secure.netroedge.com/~lm78/index.html&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When loaded, the i2c bus drivers, which talk to the i2c controller chips, export a number of files in the /proc/bus directory. When an i2c device driver is loaded and bound to an i2c device, it exports files and directories in the /proc/sys/dev/sensors directory. By moving the representation of the devices and buses to the kernel driver core, all of these separate files can be shown in their proper places in /sys.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573fd4"&gt;&lt;/a&gt;The i2c Bus&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The main i2c bus subsystem needs to be declared in the kernel and registered with the driver core. To accomplish this, the following code was added to drivers/i2c/i2c-core.c:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;static int i2c_device_match(struct device *dev,&lt;br /&gt;                          struct device_driver *drv)&lt;br /&gt;{&lt;br /&gt;    return 1;&lt;br /&gt;}&lt;br /&gt;struct bus_type i2c_bus_type = {&lt;br /&gt;    .name =    "i2c",&lt;br /&gt;    .match =   i2c_device_match,&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The name field says what the bus should be called, and the match field points to our match function. Right now, the match function is left alone, always returning 1 whenever the driver core wants to try to match a driver with a device. This logic will be modified at a later time.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Then, in the i2c core startup code, the i2c_bus_type is registered with a call to:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;bus_register(&amp;i2c_bus_type);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;When the i2c core is shut down, a call is added to unregister this bus:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;bus_unregister(&amp;i2c_bus_type);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;When the above code runs, the following tree is created in sysfs: &lt;pre class="programlisting"&gt;&lt;tt&gt;$ tree /sys/bus/i2c/&lt;br /&gt;/sys/bus/i2c/&lt;br /&gt;-- devices&lt;br /&gt;'-- drivers&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;When the i2c core is removed from the system, the above directories are removed. This is all that is needed to create the i2c bus.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x857418c"&gt;&lt;/a&gt;i2c Adapters&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;An i2c bus by itself is pretty boring. Now, the i2c bus adapter drivers need to be modified to register themselves with this bus. To do this, a struct device variable is added to the struct i2c_adapter structure:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;struct i2c_adapter {&lt;br /&gt;    ..... &lt;br /&gt;    struct device dev;&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;A to_i2c_adapter() macro is defined as:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;#define to_i2c_adapter(d) container_of(d,&lt;br /&gt;struct i2c_adapter, dev)&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;This macro is used by the i2c core to get a pointer to a real i2c_adapter structure whenever the driver core passes it a pointer to a struct device.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The struct device in the i2c_adapter is a whole variable declared within the structure, not merely a pointer. This is done so when the driver core passes a pointer to a struct device, the i2c code can use the to_i2c_adapter() macro to get a pointer to the real i2c_adapter structure.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;a href="/articles/lj/0110/6717/6717s2.html" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;Sidebar: container_of()&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The individual struct i2c_driver variables are declared in the different i2c bus drivers. For example, in the i2c-piix4.c driver, there is a variable called piix4_adapter of type struct i2c_driver. This variable is passed to the i2c core in the i2c_add_adapter() function, when a PIIX4 adapter is seen by the i2c-piix4 driver.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the i2c-piix4.c driver, before i2c_add_adapter() is called, a pointer to the parent device of the PIIX4 adapter needs to be saved within the i2c_driver structure. This is done with a single line of code:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;piix4_adapter.dev.parent = &amp;dev-&amp;gt;dev;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;dev is a pointer to the struct pci_dev that is passed to the i2c-piix4 driver's PCI probe function; the PIIX4 is a PCI-based device.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To link the i2c_driver variable to the sysfs tree, the following lines of code are added to the i2c_add_adapter() function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;/* add the adapter to the driver core.&lt;br /&gt; * The parent pointer should already&lt;br /&gt; * have been set up.&lt;br /&gt; */&lt;br /&gt;sprintf(adap-&amp;gt;dev.bus_id, "i2c-%d", i);&lt;br /&gt;strcpy(adap-&amp;gt;dev.name, "i2c controller");&lt;br /&gt;device_register(&amp;adap-&amp;gt;dev);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;With this code, when the PIIX4 device is detected by the driver, an i2c bus tree is created and linked to the controlling PCI device:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;$ tree /sys/devices/pci0/00:07.3/i2c-0&lt;br /&gt;/sys/devices/pci0/00:07.3/i2c-0&lt;br /&gt;-- name&lt;br /&gt;`-- power&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;When the i2c-piix4 driver is unloaded, the i2c_del_adapter() function is called. The following line of code is added to clean up the i2c bus device: &lt;pre class="programlisting"&gt;&lt;tt&gt;/* clean up the sysfs representation */&lt;br /&gt;device_unregister(&amp;adap-&amp;gt;dev);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85744a4"&gt;&lt;/a&gt;i2c Drivers&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The i2c bus has a number of different drivers that control access to a wide range of i2c devices that live on the i2c bus. These drivers are declared with a struct i2c_driver structure. Within this structure, a struct device_driver variable is added to allow these drivers to be registered with the driver core:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;struct i2c_driver {&lt;br /&gt;    .....&lt;br /&gt;    struct device_driver driver;&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;And, a to_i2c_driver() macro is defined as:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;#define to_i2c_driver(d) container_of(d, struct&lt;br /&gt;i2c_driver, driver)&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;An i2c driver registers itself with the i2c core in a call to i2c_add_driver(). To add driver core support for i2c drivers, the following lines of code are added to this function: &lt;pre class="programlisting"&gt;&lt;tt&gt;/* add the driver to the list of&lt;br /&gt; *i2c drivers in the driver core */&lt;br /&gt;driver-&amp;gt;driver.name = driver-&amp;gt;name;&lt;br /&gt;driver-&amp;gt;driver.bus = &amp;i2c_bus_type;&lt;br /&gt;driver-&amp;gt;driver.probe = i2c_device_probe;&lt;br /&gt;driver-&amp;gt;driver.remove = i2c_device_remove;&lt;br /&gt;&lt;br /&gt;retval = driver_register(&amp;driver-&amp;gt;driver);&lt;br /&gt;if (retval)&lt;br /&gt;    return retval;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;This sets up the driver core structure to have the same name as the driver and a bus type of i2c_bus_type; the probe and remove functions are set to local i2c functions. For now, these functions are declared as: &lt;pre class="programlisting"&gt;&lt;tt&gt;int i2c_device_probe(struct device *dev)&lt;br /&gt;{&lt;br /&gt;    return -ENODEV;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int i2c_device_remove(struct device *dev)&lt;br /&gt;{&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;because no i2c device support has been added yet. These functions will be called when an i2c device is added or removed from the driver core, but that will be described in the next column.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;When the i2c_add_driver() is called, the driver is registered with the i2c_bus_type, and it shows up in sysfs as:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;$ tree /sys/bus/i2c/&lt;br /&gt;/sys/bus/i2c/&lt;br /&gt;-- devices&lt;br /&gt;`-- drivers&lt;br /&gt;    -- EEPROM READER&lt;br /&gt;    `-- W83781D sensors&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;To remove an i2c driver from the system, the i2c_del_driver() function is called. In order to remove the i2c driver from the driver core that was registered with the call to driver_register, the following line of code is added to this function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;driver_unregister(&amp;driver-&amp;gt;driver);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85746b4"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;We have covered the basics of the new driver core, and to help understand how this driver model affects different subsystems, we covered the changes needed to convert the i2c core to support the kernel core bus and driver model. In the next Driving Me Nuts column, we will cover how to add i2c device support and how the probe() and remove() functions should look.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111202413982274874?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111202413982274874/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111202413982274874' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202413982274874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202413982274874'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/driver-model-core-part-i.html' title='The Driver Model Core, Part I'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111202401230038996</id><published>2005-03-28T07:32:00.000-08:00</published><updated>2005-03-28T07:33:32.340-08:00</updated><title type='text'>I2C Drivers, Part II</title><content type='html'>&lt;h1 class="title"&gt;&lt;span class="submitted"&gt;&lt;span style="font-size:85%;color:#999999;"&gt;By &lt;/span&gt;&lt;a title="View user profile." href="user/800887"&gt;&lt;strong&gt;&lt;span style="font-size:85%;color:#000000;"&gt;Greg Kroah-Hartman&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;span style="font-size:85%;color:#999999;"&gt; on Sun, 2004-02-01 00:00.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/h1&gt;&lt;div class="node "&gt;&lt;div class="content"&gt;&lt;br /&gt;&lt;p style="COLOR: red"&gt;&lt;/p&gt;Here's what has to happen to read the sensors that report the temperature, fan speed and other important system health information.&lt;br /&gt;&lt;div class="article" lang="en"&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573984"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In my last column [&lt;span class="emphasis"&gt;&lt;em&gt;LJ&lt;/em&gt;&lt;/span&gt;, December 2003], we discussed how I2C bus drivers and I2C algorithm drivers work. We also described how to make a tiny dummy I2C bus driver. This month, we discuss how an I2C chip driver works and provide an example of one in action.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;An I2C chip driver controls the process of talking to an individual I2C device that lives on an I2C bus. I2C chip devices usually monitor a number of different physical devices on a motherboard, such as the different fan speeds, temperature values and voltages.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The struct i2c_driver structure describes a I2C chip driver. This structure is defined in the include/linux/i2c.h file. Only the following fields are necessary to create a working chip driver:&lt;/p&gt;&lt;br /&gt;&lt;div class="itemizedlist"&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;struct module *owner; - set to the value THIS_MODULE that allows the proper module reference counting.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;char name[I2C_NAME_SIZE]; - set to a descriptive name of the I2C chip driver. This value shows up in the sysfs file name created for every I2C chip device.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;unsigned int flags; - set to the value I2C_DF_NOTIFY in order for the chip driver to be notified of any new I2C devices loaded after this driver is loaded. This field probably will go away soon, as almost all drivers set this field.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;int (*attach_adapter)(struct i2c_adapter *); - called whenever a new I2C bus driver is loaded in the system. This function is described in more detail below.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;int (*detach_client)(struct i2c_client *); - called when the i2c_client device is to be removed from the system. More information about this function is provided below.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The following code is from an example I2C chip driver called tiny_i2c_chip.c., which is available from the &lt;span class="emphasis"&gt;&lt;em&gt;Linux Journal&lt;/em&gt;&lt;/span&gt; FTP site [&lt;a href="ftp://ftp.ssc.com/pub/lj/listings/issue118/7252.tgz" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;ftp.ssc.com/pub/lj/listings/issue118/7252.tgz&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;]. It shows how the struct i2c_driver structure is set up:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static struct i2c_driver chip_driver = {&lt;br /&gt;    .owner          = THIS_MODULE,&lt;br /&gt;    .name           = "tiny_chip",&lt;br /&gt;    .flags          = I2C_DF_NOTIFY,&lt;br /&gt;    .attach_adapter = chip_attach_adapter,&lt;br /&gt;    .detach_client  = chip_detach_client,&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573d20"&gt;&lt;/a&gt;Registering a Chip Driver&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;To register this I2C chip driver, the function i2c_add_driver should be called with a pointer to the struct i2c_driver: &lt;span class="c2"&gt;Garrick, please kern the double underscores below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static int __init tiny_init(void)&lt;br /&gt;{&lt;br /&gt;    return i2c_add_driver(&amp;amp;chip_driver);&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To unregister the I2C chip driver, the i2c_del_driver function should be called with the same pointer to the struct i2c_driver:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static void __exit tiny_exit(void)&lt;br /&gt;{&lt;br /&gt;    i2c_del_driver(&amp;amp;chip_driver);&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;After the I2C chip driver is registered, the attach_adapter function callback is called when an I2C bus driver is loaded. This function checks to see if any I2C devices are on this I2C bus to which the client driver wants to attach. Almost all I2C chip drivers call the core I2C function i2c_detect to determine this. For example, the tiny_i2c_chip.c driver does this:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static int&lt;br /&gt;chip_attach_adapter(struct i2c_adapter *adapter)&lt;br /&gt;{&lt;br /&gt;    return i2c_detect(adapter, &amp;amp;addr_data,&lt;br /&gt;                      chip_detect);&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The i2c_detect function probes the I2C adapter, looking for the different addresses specified in the addr_data structure. If a device is found, the chip_detect function then is called.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If you look closely at the source code, you cannot find the addr_data structure anywhere. The reason for this is it is created by the SENSORS_INSMOD_1 macro. This macro is defined in the include/linux/i2c-sensor.h file and is quite complicated. It sets up a static variable called addr_data based on the number of different types of chips that this driver supports and the addresses at which these chips typically are present. It then provides the ability to override these values by using module parameters. An I2C chip driver must provide the variables normal_i2c, normal_i2c_range, normal_isa and normal_isa_range. These variables define the i2c smbus and i2c isa addresses this chip driver supports. They are an array of addresses, all terminated by either the special value I2C_CLIENT_END or I2C_CLIENT_ISA_END. &lt;u&gt;Usually a specific type of I2C chip shows up in only a limited range of addresses.&lt;/u&gt; The tiny_i2c_client.c driver defines these variables as:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static unsigned short normal_i2c[] =&lt;br /&gt;  { I2C_CLIENT_END };&lt;br /&gt;static unsigned short normal_i2c_range[] =&lt;br /&gt;  { 0x00, 0xff, I2C_CLIENT_END };&lt;br /&gt;static unsigned int normal_isa[] =&lt;br /&gt;  { I2C_CLIENT_ISA_END };&lt;br /&gt;static unsigned int normal_isa_range[] =&lt;br /&gt;  { I2C_CLIENT_ISA_END };&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The normal_i2c_range variable specifies that we can find this chip device at any I2C smbus address. This allows us to test this driver on almost any I2C bus driver.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573f88"&gt;&lt;/a&gt;What to Do When the Chip Is Found&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the tiny_i2c_chip.c driver, when an I2C chip device is found, the function chip_detect is called by the I2C core. This function is declared with the following parameters:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static int&lt;br /&gt;chip_detect(struct i2c_adapter *adapter,&lt;br /&gt;            int address, int kind);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The adapter variable is the I2C adapter structure on which this chip is located. The address variable contains the address where the chip was found, and the kind variable indicates what kind of chip was found. The kind variable usually is ignored, but some I2C chip drivers support different kinds of I2C chips, so this variable can be used to determine the type of chip present.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This function is responsible for creating a struct i2c_client structure that then is registered with the I2C core. The I2C core uses that structure as an individual I2C chip device. To create this structure, the chip_detect function does the following:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;struct i2c_client *new_client = NULL;&lt;br /&gt;struct chip_data *data = NULL;&lt;br /&gt;int err = 0;&lt;br /&gt;new_client = kmalloc(sizeof(*new_client),&lt;br /&gt;                     GFP_KERNEL);&lt;br /&gt;if (!new_client) {&lt;br /&gt;    err = -ENOMEM;&lt;br /&gt;    goto error;&lt;br /&gt;}&lt;br /&gt;memset(new_client, 0x00, sizeof(*new_client));&lt;br /&gt;data = kmalloc(sizeof(*data), GFP_KERNEL);&lt;br /&gt;if (!data) {&lt;br /&gt;    err = -ENOMEM;&lt;br /&gt;    goto error;&lt;br /&gt;}&lt;br /&gt;memset(data, 0x00, sizeof(*data));&lt;br /&gt;i2c_set_clientdata(new_client, data);&lt;br /&gt;new_client-&amp;gt;addr = address;&lt;br /&gt;new_client-&amp;gt;adapter = adapter;&lt;br /&gt;new_client-&amp;gt;driver = &amp;amp;chip_driver;&lt;br /&gt;new_client-&amp;gt;flags = 0;&lt;br /&gt;strncpy(new_client-&amp;gt;name, "tiny_chip",&lt;br /&gt;        I2C_NAME_SIZE);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;First, the struct i2c_client structure and a separate local data structure (called struct chip_data) are created and initialized to zero. It is important that the i2c_client structure is initialized to zero, as the lower levels of the kernel driver core require this in order to work properly. After the memory is allocated successfully, some fields in the struct i2c_client are set to point to this specific device and this specific driver. Notably, the addr, adapter and driver variables must be initialized. The name of the struct i2c_client also must be set if it is to show up properly in the sysfs tree for this I2C device.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After the struct i2c_client structure is initialized, it must be registered with the I2C core. This is done with a call to the i2c_attach_client function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;/* Tell the I2C layer a new client has arrived */&lt;br /&gt;err = i2c_attach_client(new_client);&lt;br /&gt;if (err)&lt;br /&gt;    goto error;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;When this function returns, with no errors reported, the I2C chip device is set up properly in the kernel.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x857416c"&gt;&lt;/a&gt;I2C and sysfs&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the 2.0, 2.2 and 2.4 kernels, the I2C code would place the I2C chip devices in the /proc/bus/i2c directory. In the 2.6 kernel, all I2C chip devices and adapters show up in the sysfs filesystem. I2C chip devices can be found at /sys/bus/i2c/devices, listed by their adapter address and chip address. For example, the tiny_i2c_chip driver loaded on a machine might produce the following sysfs tree structure:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;&lt;span class="c2"&gt;Garrick, use small font size for the listing below.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;$ tree /sys/bus/i2c/&lt;br /&gt;/sys/bus/i2c/&lt;br /&gt;-- devices&lt;br /&gt;   -- 0-0009 -&amp;gt; ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0009&lt;br /&gt;   -- 0-000a -&amp;gt; ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000a&lt;br /&gt;   -- 0-000b -&amp;gt; ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000b&lt;br /&gt;   `-- 0-0019 -&amp;gt; ../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0019&lt;br /&gt;`-- drivers&lt;br /&gt;    -- i2c_adapter&lt;br /&gt;    `-- tiny_chip&lt;br /&gt;        -- 0-0009 -&amp;gt; ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0009&lt;br /&gt;        -- 0-000a -&amp;gt; ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000a&lt;br /&gt;        -- 0-000b -&amp;gt; ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-000b&lt;br /&gt;        `-- 0-0019 -&amp;gt; ../../../../devices/pci0000:00/0000:00:06.0/i2c-0/0-0019&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This shows four different I2C chip devices, all controlled by the same tiny_chip driver. The controlling driver can be located by looking at the devices in the /sys/bus/i2c/drivers directory or by looking in the directory of the chip device itself and reading the name file: &lt;span class="c2"&gt;Garrick, please use small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ cat /sys/devices/pci0000\:00/0000\:00\:06.0/i2c-0/0-0009/name&lt;br /&gt;tiny_chip&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;All I2C chip drivers export the different sensor values through sysfs files within the I2C chip device directory. These filenames are standardized, along with the units in which the values are expressed, and are documented within the kernel tree in the file Documentation/i2c/sysfs-interface (Table 1).&lt;/p&gt;&lt;br /&gt;&lt;div class="table"&gt;&lt;a name="N0x850ca10.0x85742f8"&gt;&lt;/a&gt;&lt;br /&gt;&lt;p class="title c1"&gt;Table 1. Sensor Values Exported through sysfs Files&lt;/p&gt;&lt;br /&gt;&lt;table summary="Table 1. Sensor Values Exported through sysfs Files7252t1.qrk" border="1"&gt;&lt;br /&gt;&lt;colgroup&gt;&lt;br /&gt;&lt;colgroup&gt;&lt;col&gt;&lt;br /&gt;&lt;colgroup&gt;&lt;col&gt;&lt;/colgroup&gt;&lt;br /&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;temp_max[1-3]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Temperature max value. Fixed point value in form XXXXX and should be divided by 1,000 to get degrees Celsius. Read/Write value.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;temp_min[1-3]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Temperature min or hysteresis value. Fixed point value in form XXXXX and should be divided by 1,000 to get degrees Celsius. This is preferably a hysteresis value, reported as an absolute temperature, &lt;span class="emphasis"&gt;&lt;em&gt;not&lt;/em&gt;&lt;/span&gt; a delta from the max value. Read/Write value.&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;temp_input[1-3]&lt;/td&gt;&lt;br /&gt;&lt;td&gt;Temperature input value. Read-only value.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;As the information in Table 1 shows, there is only one value per file. All files are readable and some can be written to by users with the proper privileges.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The tiny_i2c_chip.c driver emulates an I2C chip device that can report temperature values. It creates the files, temp_max1, temp_min1 and temp_input1 in sysfs. The values it returns when these files are read from is incremented every time the file is read to show how to access different unique chip values.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In order to create a file in sysfs, the DEVICE_ATTR macro is used:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static DEVICE_ATTR(temp_max, S_IWUSR  S_IRUGO,&lt;br /&gt;                   show_temp_max, set_temp_max);&lt;br /&gt;static DEVICE_ATTR(temp_min, S_IWUSR  S_IRUGO,&lt;br /&gt;                   show_temp_hyst, set_temp_hyst);&lt;br /&gt;static DEVICE_ATTR(temp_input, S_IRUGO,&lt;br /&gt;                   show_temp_input, NULL);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;This macro creates a structure that then is passed to the function device_create_file at the end of the chip_detect function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;/* Register sysfs files */&lt;br /&gt;device_create_file(&amp;new_client-&amp;gt;dev,&lt;br /&gt;                   &amp;amp;dev_attr_temp_max);&lt;br /&gt;device_create_file(&amp;new_client-&amp;gt;dev,&lt;br /&gt;                   &amp;amp;dev_attr_temp_min);&lt;br /&gt;device_create_file(&amp;new_client-&amp;gt;dev,&lt;br /&gt;                   &amp;amp;dev_attr_temp_input);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574694"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;That call creates the sysfs files for the device:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;/sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009&lt;br /&gt;-- detach_state&lt;br /&gt;-- name&lt;br /&gt;-- power&lt;br /&gt;   `-- state&lt;br /&gt;-- temp_input&lt;br /&gt;-- temp_max&lt;br /&gt;`-- temp_min&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The file name is created by the I2C core, and the files detach_state and power/state are created by the driver core.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;But, let's go back to the DEVICE_ATTR macro. That macro wants to know the name of the file to be created, the mode of the file to be created, the name of the function to be called when the file is read from and the name of the function to be called when the file is written to. For the file temp_max, this declaration was:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static DEVICE_ATTR(temp_max, S_IWUSR  S_IRUGO,&lt;br /&gt;                   show_temp_max, set_temp_max);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The function called when the file is read from is show_temp_max. This is defined, as are many sysfs files, with another macro that creates a function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;#define show(value) static ssize_t show_##value(struct device *dev, char *buf)        {                                                      struct i2c_client *client = to_i2c_client(dev);    struct chip_data *data =                               i2c_get_clientdata(client);                                                                       chip_update_client(client);                        return sprintf(buf, "%d\n", data-&amp;gt;value);      }&lt;br /&gt;show(temp_max);&lt;br /&gt;show(temp_hyst);&lt;br /&gt;show(temp_input);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2bd8"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The reason this function is created with a macro is that it is quite simple to create other sysfs files that do almost the same thing, with different names and that read from different variables, without having to duplicate code. This single macro creates three different functions to read from three different variables from the struct chip_data structure.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In this function, the struct device * is converted into a struct i2c_client *. Then the private struct chip_data * is obtained from the struct i2c_client *. After that the chip data is updated with a call to chip_update_client. From there, the variable that has been asked for is printed into a buffer and returned to the driver core, which then returns it to the user: &lt;span class="c2"&gt;Garrick, please use a small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;           &lt;br /&gt;$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input&lt;br /&gt;1&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The chip_update_client increments all values by one every time it is called: &lt;span class="c2"&gt;Garrick, please kern the double underscores below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static void&lt;br /&gt;chip_update_client(struct i2c_client *client)&lt;br /&gt;{&lt;br /&gt;    struct chip_data *data =&lt;br /&gt;        i2c_get_clientdata(client);&lt;br /&gt;    down(&amp;data-&amp;gt;update_lock);&lt;br /&gt;    dev_dbg(&amp;client-&amp;gt;dev, "%s\n", __FUNCTION__);&lt;br /&gt;    ++data-&amp;gt;temp_input;&lt;br /&gt;    ++data-&amp;gt;temp_max;&lt;br /&gt;    ++data-&amp;gt;temp_hyst;&lt;br /&gt;    data-&amp;gt;last_updated = jiffies;&lt;br /&gt;    data-&amp;gt;valid = 1;&lt;br /&gt;    up(&amp;data-&amp;gt;update_lock);&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2d64"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;So, all subsequent requests for this value are different: &lt;span class="c2"&gt;Garrick, please use small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input&lt;br /&gt;2&lt;br /&gt;$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_input&lt;br /&gt;3&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The set_temp_max function also is created from a macro to allow variables to be written to:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;#define set(value, reg) static ssize_t                                     set_##value(struct device *dev,                                const char *buf, size_t count)         {                                                      struct i2c_client *client = to_i2c_client(dev);    struct chip_data *data =                               i2c_get_clientdata(client);                    int temp = simple_strtoul(buf, NULL, 10);                                                             down(&amp;data-&amp;gt;update_lock);                          data-&amp;gt;value = temp;                                up(&amp;data-&amp;gt;update_lock);                            return count;                                  }&lt;br /&gt;set(temp_max, REG_TEMP_OS);&lt;br /&gt;set(temp_hyst, REG_TEMP_HYST);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Just like the show functions, this function converts the struct device * to a struct i2c_client *, and then the private struct chip_data * is found. The data the user provides then is turned into a number with a call to simple_strtoul and is saved into the proper variable: &lt;span class="c2"&gt;Garrick, please use small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max&lt;br /&gt;1&lt;br /&gt;$ echo 41 &amp;gt; /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max&lt;br /&gt;$ cat /sys/devices/pci0000:00/0000:00:06.0/i2c-0/0-0009/temp_max&lt;br /&gt;42&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d2f1c"&gt;&lt;/a&gt;Cleaning Up&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;When the I2C chip device is removed from the system, either by the I2C bus driver being unloaded or by the I2C chip driver being unloaded, the I2C core calls the detatch_client function specified in the struct i2c_driver structure. This usually is a simple function, as can be seen in the example driver's implementation: &lt;span class="c2"&gt;Garrick, please use small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static int chip_detach_client(struct i2c_client *client)&lt;br /&gt;{&lt;br /&gt;    struct chip_data *data = i2c_get_clientdata(client);&lt;br /&gt;    int err;&lt;br /&gt;    err = i2c_detach_client(client);&lt;br /&gt;    if (err) {&lt;br /&gt;        dev_err(&amp;client-&amp;gt;dev,&lt;br /&gt;                "Client deregistration failed, "&lt;br /&gt;                "client not detached.\n");&lt;br /&gt;        return err;&lt;br /&gt;    }&lt;br /&gt;    kfree(client);&lt;br /&gt;    kfree(data);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;As the i2c_attach_client function was called to register the struct i2c_client structure with the I2C core, the i2c_detach_client function must be called to unregister it. If that function succeeds, the memory the driver has allocated for the I2C device then needs to be freed before returning from the function.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This example driver does not specifically remove the sysfs files from the sysfs core. This step is done automatically in the driver core within the i2c_detach_client function. But if the author would like, the file can be removed manually by a call to device_remove_file.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x85d3050"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This two-part series of articles has explained the basics of how to write a kernel I2C bus driver, I2C algorithm driver and I2C chip driver. A lot of good information on how to write I2C drivers can be found in the Documentation/i2c directory in the kernel tree and on the Lm_sensors Web site (&lt;a href="http://secure.netroedge.com/~lm78" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;secure.netroedge.com/~lm78&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;).&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things, and can be reached at &lt;a href="mailto:greg@kroah.com"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;greg@kroah.com&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;. &lt;span class="c2"&gt;7252aa.tif&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111202401230038996?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111202401230038996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111202401230038996' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202401230038996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202401230038996'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/i2c-drivers-part-ii.html' title='I2C Drivers, Part II'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11751455.post-111202212422175842</id><published>2005-03-28T07:00:00.000-08:00</published><updated>2005-03-28T07:02:04.246-08:00</updated><title type='text'>I2C Drivers, Part I</title><content type='html'>&lt;h1 class="title"&gt;&lt;span class="submitted"&gt;&lt;span style="font-size:85%;color:#999999;"&gt;By &lt;/span&gt;&lt;a title="View user profile." href="user/800887"&gt;&lt;strong&gt;&lt;span style="font-size:85%;color:#000000;"&gt;Greg Kroah-Hartman&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;&lt;span style="font-size:85%;color:#999999;"&gt; on Mon, 2003-12-01 00:00.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/h1&gt;&lt;div class="node "&gt;&lt;div class="content"&gt;&lt;br /&gt;&lt;p style="COLOR: red"&gt;&lt;/p&gt;The I2C bus helps you monitor the health of your system. Here's how to develop a driver that will get you all the hardware info you need to know.&lt;br /&gt;&lt;div class="article" lang="en"&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573984"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In the June and August 2003 issues of &lt;span class="emphasis"&gt;&lt;em&gt;Linux Journal&lt;/em&gt;&lt;/span&gt;, my column covered the Linux kernel driver model, and the I2C subsystem was used as an example. This month, we discuss what the I2C subsystem does and how to write a driver for it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I2C is the name for a two-wire serial bus protocol originally developed by Phillips. It commonly is used in embedded systems so different components can communicate; PC motherboards use I2C to talk to different sensor chips. Those sensors typically report back fan speeds, processor temperatures and a whole raft of system hardware information. The protocol also is used in some RAM chips to report information about the DIMM itself back to the operating system.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The I2C kernel code has lived outside of the main kernel tree for much of its development life-it originally was written back in the 2.0 days. The 2.4 kernel contains a bit of I2C support, mainly for some video drivers. With the 2.6 kernel, a large portion of the I2C code has made it into the main kernel tree, thanks to the effort of a number of kernel developers who changed the interfaces to be more acceptable to the kernel community. A few drivers still live only in the external CVS tree and have not been moved into the main kernel.org tree, but it is only a matter of time before they, too, are ported.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The I2C kernel code is broken up into a number of logical pieces: the I2C core, I2C bus drivers, I2C algorithm drivers and I2C chip drivers. We ignore how the I2C core operates in this article and focus instead on how to write a bus and algorithm driver. In Part II, we will cover how to write an I2C chip driver.&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573ab8"&gt;&lt;/a&gt;I2C Bus Drivers&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;An I2C bus driver is described by a struct named i2c_adapter, which is defined in the include/linux/i2c.h file. Only the following fields need to be set up by the bus driver:&lt;/p&gt;&lt;br /&gt;&lt;div class="itemizedlist"&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;struct module *owner; -set to the value (THIS_MODULE) that allows the proper module reference counting.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;unsigned int class; -the type of I2C class devices that this driver supports. Usually this is set to the value I2C_ADAP_CLASS_SMBUS.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;struct i2c_algorithm *algo; -a pointer to the struct i2c_algorithm structure that describes the way data is transferred through this I2C bus controller. More information on this structure is provided below.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;char name[I2C_NAME_SIZE]; -set to a descriptive name of the I2C bus driver. This value shows up in the sysfs filename associated with this I2C adapter.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The code below comes from an example I2C adapter driver called tiny_i2c_adap.c, available from the &lt;span class="emphasis"&gt;&lt;em&gt;Linux Journal&lt;/em&gt;&lt;/span&gt; FTP site [&lt;a href="ftp://ftp.ssc.com/pub/lj/listings/issue116/7136.tgz" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;ftp.ssc.com/pub/lj/listings/issue116/7136.tgz&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;] and shows how the struct i2c_adapter is set up:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static struct i2c_adapter tiny_adapter = {&lt;br /&gt;    .owner  = THIS_MODULE,&lt;br /&gt;    .class  = I2C_ADAP_CLASS_SMBUS,&lt;br /&gt;    .algo   = &amp;amp;tiny_algorithm,&lt;br /&gt;    .name   = "tiny adapter",&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To register this I2C adapter, the driver calls the function i2c_add_adapter with a pointer to the struct i2c_adapter:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;retval = i2c_add_adapter(&amp;amp;tiny_adapter);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;If the I2C adapter lives on a type of device that has a struct device associated with it, such as a PCI or USB device, then before the call to i2c_add_adapter, the adapter device's parent pointer should be set to that device. This pointer configuration can be seen in the following line from the drivers/i2c/busses/i2c-piix4.c driver:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;/* set up sysfs linkage to our parent device */&lt;br /&gt;piix4_adapter.dev.parent = &amp;dev-&amp;gt;dev;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;If this parent pointer is not set up, the I2C adapter is positioned on the legacy bus and shows up in the sysfs tree at /sys/devices/legacy. Here is what happens to our example driver when it is registered:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ tree /sys/devices/legacy/&lt;br /&gt;/sys/devices/legacy/&lt;br /&gt;-- detach_state&lt;br /&gt;-- floppy0&lt;br /&gt;   -- detach_state&lt;br /&gt;   `-- power&lt;br /&gt;       `-- state&lt;br /&gt;-- i2c-0&lt;br /&gt;   -- detach_state&lt;br /&gt;   -- name&lt;br /&gt;   `-- power&lt;br /&gt;       `-- state&lt;br /&gt;`-- power&lt;br /&gt;    `-- state&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;As discussed in the previous kernel driver model columns, the I2C adapter also shows up in the /sys/class/i2c-adapter directory:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ tree /sys/class/i2c-adapter/&lt;br /&gt;/sys/class/i2c-adapter/&lt;br /&gt;`-- i2c-0&lt;br /&gt;    -- device -&amp;gt; ../../../devices/legacy/i2c-0&lt;br /&gt;    `-- driver -&amp;gt; ../../../bus/i2c/drivers/i2c_adapter&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;To unregister an I2C adapter, the driver should call the function i2c_del_adapter with a pointer to the struct i2c_adapter, like this:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;i2c_del_adapter(&amp;amp;tiny_adapter);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8573f30"&gt;&lt;/a&gt;I2C Algorithm Drivers&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;An I2C algorithm is used by the I2C bus driver to talk to the I2C bus. Most I2C bus drivers define their own I2C algorithms and use them, as they are tied closely to how the bus driver talks to that specific type of hardware. For some classes of I2C bus drivers, a number of I2C algorithm drivers already have been written. Examples of these are ITE adapters found in drivers/i2c/i2c-algo-ite.c, IBM PPC 405 adapters found in drivers/i2c/i2c-algo-ibm_ocp.c and a generic I2C bit shift algorithm found in drivers/i2c/i2c-algo-bit.c. All of these already written algorithms have their own functions with which an I2C bus driver needs to register to use. For more information on these, please see all of the drivers/i2c/i2c-algo-*.c files in the kernel tree.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For our example driver, we are going to create our own I2C algorithm driver. An algorithm driver is defined by a struct i2c_algorithm structure and is defined in the include/linux/i2c.h file. Here is a description of some of the commonly used fields:&lt;/p&gt;&lt;br /&gt;&lt;div class="itemizedlist"&gt;&lt;br /&gt;&lt;ul type="disc"&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;char name[32];: the name of the algorithm.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;unsigned int id;: description of the type of algorithm this structure defines. These different types are defined in the include/linux/i2c-id.h file and start with the characters I2C_ALGO_.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[], int num);: a function pointer to be set if this algorithm driver can do I2C direct-level accesses. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the smbus_xfer function is used instead.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data);: a function pointer to be set if this algorithm driver can do SMB bus accesses. Most PCI-based I2C bus drivers are able to do this, and they should set this function pointer. If it is set, this function is called whenever an I2C chip driver wants to communicate with the chip device. If it is set to NULL, the master_xfer function is used instead.&lt;/p&gt;&lt;br /&gt;&lt;li&gt;&lt;br /&gt;&lt;p&gt;u32 (*functionality) (struct i2c_adapter *);: a function pointer called by the I2C core to determine what kind of reads and writes the I2C adapter driver can do.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;In our example I2C adapter driver, the i2c_adapter structure referenced the tiny_algorithm variable. That structure is defined as the following:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static struct i2c_algorithm tiny_algorithm = {&lt;br /&gt;    .name           = "tiny algorithm",&lt;br /&gt;    .id             = I2C_ALGO_SMBUS,&lt;br /&gt;    .smbus_xfer     = tiny_access,&lt;br /&gt;    .functionality  = tiny_func,&lt;br /&gt;};&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The tiny_func function is small and tells the I2C core what types of I2C messages this algorithm can support. For this driver, we want to be able to support a few different I2C message types:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static u32 tiny_func(struct i2c_adapter *adapter)&lt;br /&gt;{&lt;br /&gt;    return I2C_FUNC_SMBUS_QUICK&lt;br /&gt;           I2C_FUNC_SMBUS_BYTE&lt;br /&gt;           I2C_FUNC_SMBUS_BYTE_DATA&lt;br /&gt;           I2C_FUNC_SMBUS_WORD_DATA&lt;br /&gt;           I2C_FUNC_SMBUS_BLOCK_DATA;&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574274"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;All of the different I2C message types are defined in include/linux/i2c.h and start with the characters I2C_FUNC_.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The tiny_access function is called when an I2C client driver wants to talk to the I2C bus. Our example function is quite simple; it merely logs all of the requests the I2C chip driver makes to the syslog and reports success back to the caller. This log allows you to see all of the different addresses and data types that an I2C chip driver may request. The implementation looks like: &lt;span class="c2"&gt;Garrick, please kern the double underscores in the code below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;static s32 tiny_access(struct i2c_adapter *adap,&lt;br /&gt;                       u16 addr,&lt;br /&gt;                       unsigned short flags,&lt;br /&gt;                       char read_write,&lt;br /&gt;                       u8 command,&lt;br /&gt;                       int size,&lt;br /&gt;                       union i2c_smbus_data *data)&lt;br /&gt;{&lt;br /&gt;    int i, len;&lt;br /&gt;    dev_info(&amp;adap-&amp;gt;dev, "%s was called with the "&lt;br /&gt;             "following parameters:\n",&lt;br /&gt;             __FUNCTION__);&lt;br /&gt;    dev_info(&amp;adap-&amp;gt;dev, "addr = %.4x\n", addr);&lt;br /&gt;    dev_info(&amp;adap-&amp;gt;dev, "flags = %.4x\n", flags);&lt;br /&gt;    dev_info(&amp;adap-&amp;gt;dev, "read_write = %s\n",&lt;br /&gt;             read_write == I2C_SMBUS_WRITE ?&lt;br /&gt;             "write" : "read");&lt;br /&gt;    dev_info(&amp;adap-&amp;gt;dev, "command = %d\n",&lt;br /&gt;             command);&lt;br /&gt;    switch (size) {&lt;br /&gt;    case I2C_SMBUS_PROC_CALL:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_PROC_CALL\n");&lt;br /&gt;        break;&lt;br /&gt;    case I2C_SMBUS_QUICK:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_QUICK\n");&lt;br /&gt;        break;&lt;br /&gt;    case I2C_SMBUS_BYTE:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_BYTE\n");&lt;br /&gt;        break;&lt;br /&gt;    case I2C_SMBUS_BYTE_DATA:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_BYTE_DATA\n");&lt;br /&gt;        if (read_write == I2C_SMBUS_WRITE)&lt;br /&gt;            dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                     "data = %.2x\n", data-&amp;gt;byte);&lt;br /&gt;        break;&lt;br /&gt;    case I2C_SMBUS_WORD_DATA:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_WORD_DATA\n");&lt;br /&gt;        if (read_write == I2C_SMBUS_WRITE)&lt;br /&gt;            dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                     "data = %.4x\n", data-&amp;gt;word);&lt;br /&gt;        break;&lt;br /&gt;    case I2C_SMBUS_BLOCK_DATA:&lt;br /&gt;        dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                 "size = I2C_SMBUS_BLOCK_DATA\n");&lt;br /&gt;        if (read_write == I2C_SMBUS_WRITE) {&lt;br /&gt;            dev_info(&amp;adap-&amp;gt;dev, "data = %.4x\n",&lt;br /&gt;                     data-&amp;gt;word);&lt;br /&gt;            len = data-&amp;gt;block[0];&lt;br /&gt;            if (len &amp;lt; 0)&lt;br /&gt;                len = 0;&lt;br /&gt;            if (len &amp;gt; 32)&lt;br /&gt;                len = 32;&lt;br /&gt;            for (i = 1; i &amp;lt;= len; i++)&lt;br /&gt;                dev_info(&amp;adap-&amp;gt;dev,&lt;br /&gt;                         "data-&amp;gt;block[%d] = %x\n",&lt;br /&gt;                         i, data-&amp;gt;block[i]);&lt;br /&gt;        }&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Now that the tiny_i2c_adap driver is built and loaded, what can it do? On its own, it cannot do anything. An I2C bus driver needs an I2C client driver in order to do anything besides sit in the sysfs tree. So, if the lm75 I2C client driver is loaded, it tries to use the tiny_i2c_adap driver to find the chip for which it was written: &lt;span class="c2"&gt;Garrick, please use a small font so these lines don't have to break.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ modprobe lm75&lt;br /&gt;$ tree /sys/bus/i2c/&lt;br /&gt;/sys/bus/i2c/&lt;br /&gt;-- devices&lt;br /&gt;   -- 0-0048 -&amp;gt; ../../../devices/legacy/i2c-0/0-0048&lt;br /&gt;   -- 0-0049 -&amp;gt; ../../../devices/legacy/i2c-0/0-0049&lt;br /&gt;   -- 0-004a -&amp;gt; ../../../devices/legacy/i2c-0/0-004a&lt;br /&gt;   -- 0-004b -&amp;gt; ../../../devices/legacy/i2c-0/0-004b&lt;br /&gt;   -- 0-004c -&amp;gt; ../../../devices/legacy/i2c-0/0-004c&lt;br /&gt;   -- 0-004d -&amp;gt; ../../../devices/legacy/i2c-0/0-004d&lt;br /&gt;   -- 0-004e -&amp;gt; ../../../devices/legacy/i2c-0/0-004e&lt;br /&gt;   `-- 0-004f -&amp;gt; ../../../devices/legacy/i2c-0/0-004f&lt;br /&gt;`-- drivers&lt;br /&gt;    -- i2c_adapter&lt;br /&gt;    `-- lm75&lt;br /&gt;        -- 0-0048 -&amp;gt; ../../../../devices/legacy/i2c-0/0-0048&lt;br /&gt;        -- 0-0049 -&amp;gt; ../../../../devices/legacy/i2c-0/0-0049&lt;br /&gt;        -- 0-004a -&amp;gt; ../../../../devices/legacy/i2c-0/0-004a&lt;br /&gt;        -- 0-004b -&amp;gt; ../../../../devices/legacy/i2c-0/0-004b&lt;br /&gt;        -- 0-004c -&amp;gt; ../../../../devices/legacy/i2c-0/0-004c&lt;br /&gt;        -- 0-004d -&amp;gt; ../../../../devices/legacy/i2c-0/0-004d&lt;br /&gt;        -- 0-004e -&amp;gt; ../../../../devices/legacy/i2c-0/0-004e&lt;br /&gt;        `-- 0-004f -&amp;gt; ../../../../devices/legacy/i2c-0/0-004f&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Because the tiny_i2c_adap driver responds with a success to every read and write request it is asked to accomplish, the lm75 I2C chip driver thinks it has found an lm75 chip at every known possible I2C address for this chip. This abundance of addresses is why I2C devices 0-0048 through 0-004f have been created. If we look at the directory for one of these devices, the sensor files for this chip driver are shown:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ tree /sys/devices/legacy/i2c-0/0-0048/&lt;br /&gt;/sys/devices/legacy/i2c-0/0-0048/&lt;br /&gt;-- detach_state&lt;br /&gt;-- name&lt;br /&gt;-- power&lt;br /&gt;   `-- state&lt;br /&gt;-- temp_input&lt;br /&gt;-- temp_max&lt;br /&gt;`-- temp_min&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8574458"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The detach_state file and power directory is created by the kernel driver core and is used for power management. It is not created by the lm75 driver. The functions of the other files in this directory are described below.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If we ask the lm75 driver for the current value of temp_max, we receive the following:&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ cat /sys/devices/legacy/i2c-0/0-0048/temp_max&lt;br /&gt;1000&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;To get that value, the lm75 driver asked the tiny_i2c_adap driver to read some addresses on the I2C bus. This request is shown in the syslog: &lt;span class="c2"&gt;Garrick, please use a really small font so this will fit without breaking the lines.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ dmesg&lt;br /&gt;i2c_adapter i2c-0: tiny_access was called with the following parameters:&lt;br /&gt;i2c_adapter i2c-0: addr = 0048&lt;br /&gt;i2c_adapter i2c-0: flags = 0000&lt;br /&gt;i2c_adapter i2c-0: read_write = read&lt;br /&gt;i2c_adapter i2c-0: command = 0&lt;br /&gt;i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA&lt;br /&gt;i2c_adapter i2c-0: tiny_access was called with the following parameters:&lt;br /&gt;i2c_adapter i2c-0: addr = 0048&lt;br /&gt;i2c_adapter i2c-0: flags = 0000&lt;br /&gt;i2c_adapter i2c-0: read_write = read&lt;br /&gt;i2c_adapter i2c-0: command = 3&lt;br /&gt;i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA&lt;br /&gt;i2c_adapter i2c-0: tiny_access was called with the following parameters:&lt;br /&gt;i2c_adapter i2c-0: addr = 0048&lt;br /&gt;i2c_adapter i2c-0: flags = 0000&lt;br /&gt;i2c_adapter i2c-0: read_write = read&lt;br /&gt;i2c_adapter i2c-0: command = 2&lt;br /&gt;i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The log file shows that the tiny_access function was called three times. The first command wanted to read a word of data from register 0 out of the device with the address 0048. The second and third reads asked for register 3 and register 2 from the same device. The commands match up with the following code from the drivers/i2c/chips/lm75.c file in the lm75_update_client function:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;data-&amp;gt;temp_input = lm75_read_value(client,&lt;br /&gt;                                   LM75_REG_TEMP);&lt;br /&gt;data-&amp;gt;temp_max = lm75_read_value(client,&lt;br /&gt;                                LM75_REG_TEMP_OS);&lt;br /&gt;data-&amp;gt;temp_hyst = lm75_read_value(client,&lt;br /&gt;                              LM75_REG_TEMP_HYST);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The lm75_read_value function in that same file contains the following code:&lt;/p&gt;&lt;pre class="programlisting"&gt;&lt;tt&gt;&lt;br /&gt;/* All registers are word-sized, except for the&lt;br /&gt;   configuration register. LM75 uses a high-byte&lt;br /&gt;   first convention, which is exactly opposite to&lt;br /&gt;   the usual practice. */&lt;br /&gt;static int lm75_read_value(struct i2c_client&lt;br /&gt;                           *client, u8 reg)&lt;br /&gt;{&lt;br /&gt;    if (reg == LM75_REG_CONF)&lt;br /&gt;        return i2c_smbus_read_byte_data(client,&lt;br /&gt;                                        reg);&lt;br /&gt;    else&lt;br /&gt;        return swap_bytes(&lt;br /&gt;               i2c_smbus_read_word_data(client,&lt;br /&gt;                                        reg));&lt;br /&gt;}&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Therefore, when the lm75 driver wants to read the value of the max temperature, it calls the lm75_read_value function with the register number, which then calls the I2C core function i2c_smbus_read_word_data. That I2C core function looks up on which I2C bus the client device is, and then it calls the I2C algorithm associated with that specific I2C bus to do the data transfer. This is the method, then, by which our tiny_i2c_adap driver is asked to complete the transfer.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If this same sysfs file is written to, the lm75 driver asks the tiny_i2c_adap driver to write some data to a specific address on the I2C bus in the same way the read was requested. This request also is shown in the syslog: &lt;span class="c2"&gt;Garrick, again, use small font below.&lt;/span&gt;&lt;/p&gt;&lt;pre class="screen"&gt;&lt;tt&gt;$ echo 300 &amp;gt; /sys/devices/legacy/i2c-0/0-0048/temp_max&lt;br /&gt;$ dmesg&lt;br /&gt;i2c_adapter i2c-0: tiny_access was called with the following parameters:&lt;br /&gt;i2c_adapter i2c-0: addr = 0048&lt;br /&gt;i2c_adapter i2c-0: flags = 0000&lt;br /&gt;i2c_adapter i2c-0: read_write = write&lt;br /&gt;i2c_adapter i2c-0: command = 3&lt;br /&gt;i2c_adapter i2c-0: size = I2C_SMBUS_WORD_DATA&lt;br /&gt;i2c_adapter i2c-0: data = 8000&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="simplesect" lang="en"&gt;&lt;br /&gt;&lt;div class="titlepage"&gt;&lt;br /&gt;&lt;h2 class="title"&gt;&lt;a name="N0x850ca10.0x8798a48"&gt;&lt;/a&gt;Conclusion&lt;/h2&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This month we covered the basics of the I2C driver subsystem and explained how to write a simple I2C bus and I2C algorithm driver that work with any existing I2C client driver. The complete driver, dmn-09-i2c-adap.c, is available from the &lt;span class="emphasis"&gt;&lt;em&gt;Linux Journal&lt;/em&gt;&lt;/span&gt; FTP site at &lt;a href="ftp://ftp.ssc.com/pub/lj/listings/issue116/7136.tgz" target="_top"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;ftp.ssc.com/pub/lj/listings/issue116/7136.tgz&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;. In Part II, we will cover how to write an I2C chip driver.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Greg Kroah-Hartman currently is the Linux kernel maintainer for a variety of different driver subsystems. He works for IBM, doing Linux kernel-related things and can be reached at &lt;a href="mailto:greg@kroah.com"&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;greg@kroah.com&lt;/span&gt;&lt;/strong&gt;&lt;/a&gt;. &lt;span class="c2"&gt;7136aa.tif&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11751455-111202212422175842?l=xyzelinux.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://xyzelinux.blogspot.com/feeds/111202212422175842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=11751455&amp;postID=111202212422175842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202212422175842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11751455/posts/default/111202212422175842'/><link rel='alternate' type='text/html' href='http://xyzelinux.blogspot.com/2005/03/i2c-drivers-part-i.html' title='I2C Drivers, Part I'/><author><name>cygwinxp</name><uri>http://www.blogger.com/profile/01253589630079186727</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
