diff options
Diffstat (limited to 'en_US.ISO8859-1')
20 files changed, 68 insertions, 8195 deletions
diff --git a/en_US.ISO8859-1/articles/contributing/article.sgml b/en_US.ISO8859-1/articles/contributing/article.sgml deleted file mode 100644 index f8145c6234..0000000000 --- a/en_US.ISO8859-1/articles/contributing/article.sgml +++ /dev/null @@ -1,480 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/handbook/contrib/chapter.sgml,v 1.467 2001/08/10 22:58:11 chern Exp $ ---> - -<chapter id="contrib"> - <chapterinfo> - <authorgroup> - <author> - <firstname>Jordan</firstname> - <surname>Hubbard</surname> - <contrib>Contributed by </contrib> - </author> - </authorgroup> - </chapterinfo> - - <title>Contributing to FreeBSD</title> - - <indexterm><primary>contributing</primary></indexterm> - <para>So you want to contribute something to FreeBSD? That is great! We can - always use the help, and FreeBSD is one of those systems that - <emphasis>relies</emphasis> on the contributions of its user base in order - to survive. Your contributions are not only appreciated, they are vital - to FreeBSD's continued growth!</para> - - <para>Contrary to what some people might also have you believe, you do not - need to be a hot-shot programmer or a close personal friend of the FreeBSD - core team in order to have your contributions accepted. The FreeBSD - Project's development is done by a large and growing number of - international contributors whose ages and areas of technical expertise - vary greatly, and there is always more work to be done than there are - people available to do it.</para> - - <para>Since the FreeBSD project is responsible for an entire operating - system environment (and its installation) rather than just a kernel or a - few scattered utilities, our <filename>TODO</filename> list also spans a - very wide range of tasks, from documentation, beta testing and - presentation to highly specialized types of kernel development. No matter - what your skill level, there is almost certainly something you can do to - help the project!</para> - - <para>Commercial entities engaged in FreeBSD-related enterprises are also - encouraged to contact us. Need a special extension to make your product - work? You will find us receptive to your requests, given that they are not - too outlandish. Working on a value-added product? Please let us know! We - may be able to work cooperatively on some aspect of it. The free software - world is challenging a lot of existing assumptions about how software is - developed, sold, and maintained throughout its life cycle, and we urge you - to at least give it a second look.</para> - - <sect1 id="contrib-what"> - <title>What Is Needed</title> - - <para>The following list of tasks and sub-projects represents something of - an amalgam of the various core team <filename>TODO</filename> lists and - user requests we have collected over the last couple of months. Where - possible, tasks have been ranked by degree of urgency. If you are - interested in working on one of the tasks you see here, send mail to the - coordinator listed by clicking on their names. If no coordinator has - been appointed, maybe you would like to volunteer?</para> - - <sect2> - <title>Ongoing Tasks</title> - - <para>Most of the tasks listed in the previous sections require either a - considerable investment of time or an in-depth knowledge of the - FreeBSD kernel (or both). However, there are also many useful tasks - which are suitable for "weekend hackers", or people without - programming skills.</para> - - <orderedlist> - <listitem> - <para>If you run FreeBSD-current and have a good Internet - connection, there is a machine <hostid - role="fqdn">current.FreeBSD.org</hostid> which builds a full - release once a day — every now and again, try and install - the latest release from it and report any failures in the - process.</para> - </listitem> - - <listitem> - <para>Read the freebsd-bugs mailing list. There might be a - problem you can comment constructively on or with patches you - can test. Or you could even try to fix one of the problems - yourself.</para> - </listitem> - - <listitem> - <para>Read through the FAQ and Handbook periodically. If anything - is badly explained, out of date or even just completely wrong, let - us know. Even better, send us a fix (SGML is not difficult to - learn, but there is no objection to ASCII submissions).</para> - </listitem> - - <listitem> - <para>Help translate FreeBSD documentation into your native language - (if not already available) — just send an email to &a.doc; - asking if anyone is working on it. Note that you are not - committing yourself to translating every single FreeBSD document - by doing this — in fact, the documentation most in need of - translation is the installation instructions.</para> - </listitem> - - <listitem> - <para>Read the freebsd-questions mailing list and &ng.misc - occasionally (or even regularly). It can be very satisfying to - share your expertise and help people solve their problems; - sometimes you may even learn something new yourself! These forums - can also be a source of ideas for things to work on.</para> - </listitem> - - <listitem> - <para>If you know of any bug fixes which have been successfully - applied to -current but have not been merged into -stable after a - decent interval (normally a couple of weeks), send the committer a - polite reminder.</para> - </listitem> - - <listitem> - <para>Move contributed software to <filename>src/contrib</filename> - in the source tree.</para> - </listitem> - - <listitem> - <para>Make sure code in <filename>src/contrib</filename> is up to - date.</para> - </listitem> - - <listitem> - <para>Build the source tree (or just part of it) with extra warnings - enabled and clean up the warnings.</para> - </listitem> - - <listitem> - <para>Fix warnings for ports which do deprecated things like using - gets() or including malloc.h.</para> - </listitem> - - <listitem> - <para>If you have contributed any ports, send your patches back to - the original author (this will make your life easier when they - bring out the next version)</para> - </listitem> - - <listitem> - <para>Suggest further tasks for this list!</para> - </listitem> - </orderedlist> - </sect2> - - <sect2> - <title>Work through the PR Database</title> - - <indexterm><primary>problem reports database</primary></indexterm> - <para>The <ulink - url="http://www.FreeBSD.org/cgi/query-pr-summary.cgi">FreeBSD PR - list</ulink> shows all the current active problem reports and - requests for enhancement that have been submitted by FreeBSD users. - Look through the open PRs, and see if anything there takes your - interest. Some of these might be very simple tasks, that just need an - extra pair of eyes to look over them and confirm that the fix in the - PR is a good one. Others might be much more complex.</para> - - <para>Start with the PRs that have not been assigned to anyone else, but - if one them is assigned to someone else, but it looks like something - you can handle, email the person it is assigned to and ask if you can - work on it—they might already have a patch ready to be tested, - or further ideas that you can discuss with them.</para> - </sect2> - </sect1> - - <sect1 id="contrib-how"> - <title>How to Contribute</title> - - <para>Contributions to the system generally fall into one or more of the - following 6 categories:</para> - - <sect2 id="contrib-general"> - <title>Bug Reports and General Commentary</title> - - <para>An idea or suggestion of <emphasis>general</emphasis> technical - interest should be mailed to the &a.hackers;. Likewise, people with - an interest in such things (and a tolerance for a - <emphasis>high</emphasis> volume of mail!) may subscribe to the - hackers mailing list by sending mail to &a.majordomo;. See <link - linkend="eresources-mail">mailing lists</link> for more information - about this and other mailing lists.</para> - - <para>If you find a bug or are submitting a specific change, please - report it using the &man.send-pr.1; program or its <ulink - url="http://www.FreeBSD.org/send-pr.html">WEB-based - equivalent</ulink>. Try to fill-in each field of the bug report. - Unless they exceed 65KB, include any patches directly in the report. - If the patch is suitable to be applied to the source tree put - <literal>[PATCH]</literal> in the synopsis of the report. - When including patches, <emphasis>do not</emphasis> use cut-and-paste - because cut-and-paste turns tabs into spaces and makes them unusable. - Consider compressing patches and using &man.uuencode.1; if they exceed - 20KB. Upload very large submissions to <ulink - url="ftp://ftp.FreeBSD.org/pub/FreeBSD/incoming/">ftp.FreeBSD.org:/pub/FreeBSD/incoming/</ulink>.</para> - - <para>After filing a report, you should receive confirmation along with - a tracking number. Keep this tracking number so that you can update - us with details about the problem by sending mail to - <email>bug-followup@FreeBSD.org</email>. Use the number as the - message subject, e.g. <literal>"Re: kern/3377"</literal>. Additional - information for any bug report should be submitted this way.</para> - - <para>If you do not receive confirmation in a timely fashion (3 days to - a week, depending on your email connection) or are, for some reason, - unable to use the &man.send-pr.1; command, then you may ask - someone to file it for you by sending mail to the &a.bugs;.</para> - </sect2> - - <sect2> - <title>Changes to the Documentation</title> - - <indexterm><primary>documentation submissions</primary></indexterm> - <para>Changes to the documentation are overseen by the &a.doc;. Send - submissions and changes (even small ones are welcome!) using - <command>send-pr</command> as described in <link - linkend="contrib-general">Bug Reports and General - Commentary</link>.</para> - </sect2> - - <sect2> - <title>Changes to Existing Source Code</title> - - <indexterm><primary>FreeBSD-current</primary></indexterm> - <para>An addition or change to the existing source code is a somewhat - trickier affair and depends a lot on how far out of date you are with - the current state of the core FreeBSD development. There is a special - on-going release of FreeBSD known as <quote>FreeBSD-current</quote> - which is made available in a variety of ways for the convenience of - developers working actively on the system. See <link - linkend="current">Staying current with FreeBSD</link> for more - information about getting and using FreeBSD-current.</para> - - <para>Working from older sources unfortunately means that your changes - may sometimes be too obsolete or too divergent for easy re-integration - into FreeBSD. Chances of this can be minimized somewhat by - subscribing to the &a.announce; and the &a.current; lists, where - discussions on the current state of the system take place.</para> - - <para>Assuming that you can manage to secure fairly up-to-date sources - to base your changes on, the next step is to produce a set of diffs to - send to the FreeBSD maintainers. This is done with the &man.diff.1; - command, with the <quote>context diff</quote> form - being preferred. For example:</para> - - <indexterm> - <primary><command>diff</command></primary> - </indexterm> - <para> - <screen>&prompt.user; <userinput>diff -c oldfile newfile</userinput></screen> - - or - - <screen>&prompt.user; <userinput>diff -c -r olddir newdir</userinput></screen> - - would generate such a set of context diffs for the given source file - or directory hierarchy. See the man page for &man.diff.1; for more - details.</para> - - <para>Once you have a set of diffs (which you may test with the - &man.patch.1; command), you should submit them for inclusion with - FreeBSD. Use the &man.send-pr.1; program as described in <link - linkend="contrib-general">Bug Reports and General Commentary</link>. - <emphasis>Do not</emphasis> just send the diffs to the &a.hackers; or - they will get lost! We greatly appreciate your submission (this is a - volunteer project!); because we are busy, we may not be able to - address it immediately, but it will remain in the PR database until we - do. Indicate your submission by including <literal>[PATCH]</literal> - in the synopsis of the report.</para> - - <indexterm> - <primary><command>uuencode</command></primary> - </indexterm> - <para>If you feel it appropriate (e.g. you have added, deleted, or - renamed files), bundle your changes into a <command>tar</command> file - and run the &man.uuencode.1; program on it. Shar archives are also - welcome.</para> - - <para>If your change is of a potentially sensitive nature, e.g. you are - unsure of copyright issues governing its further distribution or you - are simply not ready to release it without a tighter review first, - then you should send it to &a.core; directly rather than submitting it - with &man.send-pr.1;. The core mailing list reaches a much smaller - group of people who do much of the day-to-day work on FreeBSD. Note - that this group is also <emphasis>very busy</emphasis> and so you - should only send mail to them where it is truly necessary.</para> - - <para>Please refer to &man.intro.9; and &man.style.9; style for - some information on coding style. We would appreciate it if you - were at least aware of this information before submitting - code.</para> - </sect2> - - <sect2> - <title>New Code or Major Value-Added Packages</title> - - <para>In the case of a significant contribution of a large body - work, or the addition of an important new feature to FreeBSD, it - becomes almost always necessary to either send changes as uuencoded - tar files or upload them to a web or FTP site for other people to - access. If you do not have access to a web or FTP site, ask on an - appropriate FreeBSD mailing list for someone to host the changes for - you.</para> - - <para>When working with large amounts of code, the touchy subject of - copyrights also invariably comes up. Acceptable copyrights for code - included in FreeBSD are:</para> - - <orderedlist> - <indexterm><primary>BSD copyright</primary></indexterm> - <listitem> - <para>The BSD copyright. This copyright is most preferred due to - its <quote>no strings attached</quote> nature and general - attractiveness to commercial enterprises. Far from discouraging - such commercial use, the FreeBSD Project actively encourages such - participation by commercial interests who might eventually be - inclined to invest something of their own into FreeBSD.</para> - </listitem> - - <indexterm><primary>GPL</primary><see>GNU General Public License</see></indexterm> - <indexterm><primary>GNU General Public License</primary></indexterm> - <listitem> - <para>The GNU General Public License, or <quote>GPL</quote>. - This license is not quite as popular with us due to the amount - of extra effort demanded of anyone using the code for - commercial purposes, but given the sheer quantity of GPL'd code - we currently require (compiler, assembler, text formatter, etc) - it would be silly to refuse additional contributions under this - license. Code under the GPL also goes into a different part of - the tree, that being <filename>/sys/gnu</filename> or - <filename>/usr/src/gnu</filename>, and is therefore easily - identifiable to anyone for whom the GPL presents a - problem.</para> - </listitem> - </orderedlist> - - <para>Contributions coming under any other type of copyright must be - carefully reviewed before their inclusion into FreeBSD will be - considered. Contributions for which particularly restrictive - commercial copyrights apply are generally rejected, though the authors - are always encouraged to make such changes available through their own - channels.</para> - - <para>To place a <quote>BSD-style</quote> copyright on your work, include - the following text at the very beginning of every source code file you - wish to protect, replacing the text between the <literal>%%</literal> - with the appropriate information.</para> - - <programlisting>Copyright (c) %%proper_years_here%% - %%your_name_here%%, %%your_state%% %%your_zip%%. - All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer as - the first lines of this file unmodified. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY %%your_name_here%% ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL %%your_name_here%% BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - $Id$</programlisting> - - <para>For your convenience, a copy of this text can be found in - <filename>/usr/share/examples/etc/bsd-style-copyright</filename>.</para> - </sect2> - - <sect2> - <title>Money, Hardware or Internet Access</title> - - <para>We are always very happy to accept donations to further the cause - of the FreeBSD Project and, in a volunteer effort like ours, a little - can go a long way! Donations of hardware are also very important to - expanding our list of supported peripherals since we generally lack - the funds to buy such items ourselves.</para> - - <sect3> - <title><anchor id="donations">Donating Funds</title> - - <para>The FreeBSD Foundation is a non-profit, tax-exempt - foundation established to further the goals of the FreeBSD - Project. As a 501(c)3 entity, the Foundation is generally - exempt from US federal income tax as well as Colorado - State income tax. Donations to a tax-exempt entity are - often deductible from taxable federal income.</para> - - <para>Donations may be sent in check form to: - <address> - The FreeBSD Foundation - <street>7321 Brockway Dr.</street> - <city>Boulder</city>, <state>CO</state> <postcode>80303</postcode> - <country>USA</country> - </address> - The Foundation is not yet able to accept other forms - of payment such as credit cards and PayPal.</para> - - <para>More information about the FreeBSD Foundation can be - found in <ulink - url="http://people.freebsd.org/~jdp/foundation/announcement.html">The - FreeBSD Foundation -- an Introduction</ulink>. To contact - the Foundation by email, write to - <email>bod@FreeBSDFoundation.org</email>.</para> - </sect3> - - <sect3> - <title>Donating Hardware</title> - <indexterm><primary>donations</primary></indexterm> - - <para>Donations of hardware in any of the 3 following categories are - also gladly accepted by the FreeBSD Project:</para> - - <itemizedlist> - <listitem> - <para>General purpose hardware such as disk drives, memory or - complete systems should be sent to the FreeBSD, Inc. address - listed in the <emphasis>donating funds</emphasis> - section.</para> - </listitem> - - <listitem> - <para>Hardware for which ongoing compliance testing is desired. - We are currently trying to put together a testing lab of all - components that FreeBSD supports so that proper regression - testing can be done with each new release. We are still lacking - many important pieces (network cards, motherboards, etc) and if - you would like to make such a donation, please contact &a.dg; - for information on which items are still required.</para> - </listitem> - - <listitem> - <para>Hardware currently unsupported by FreeBSD for which you - would like to see such support added. Please contact the - &a.core; before sending such items as we will need to find a - developer willing to take on the task before we can accept - delivery of new hardware.</para> - </listitem> - </itemizedlist> - </sect3> - - <sect3> - <title>Donating Internet Access</title> - - <para>We can always use new mirror sites for FTP, WWW or - <command>cvsup</command>. If you would like to be such a mirror, - please contact the FreeBSD project administrators - <email>hubs@FreeBSD.org</email> for more information.</para> - </sect3> - </sect2> - </sect1> - -</chapter> - -<!-- - Local Variables: - mode: sgml - sgml-declaration: "../chapter.decl" - sgml-indent-data: t - sgml-omittag: nil - sgml-always-quote-attributes: t - sgml-parent-document: ("../book.sgml" "part" "chapter") - End: ---> diff --git a/en_US.ISO8859-1/books/arch-handbook/Makefile b/en_US.ISO8859-1/books/arch-handbook/Makefile deleted file mode 100644 index a0e84f24d3..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/Makefile,v 1.6 2001/06/23 04:57:31 murray Exp $ -# -# Build the FreeBSD Developers' Handbook. -# - -MAINTAINER=asmodai@FreeBSD.org - -DOC?= book - -FORMATS?= html-split - -INSTALL_COMPRESSED?= gz -INSTALL_ONLY_COMPRESSED?= - -GEN_INDEX?= yes - -# Images -IMAGES= sockets/layers.eps sockets/sain.eps sockets/sainfill.eps sockets/sainlsb.eps sockets/sainmsb.eps sockets/sainserv.eps sockets/serv.eps sockets/serv2.eps sockets/slayers.eps - -# -# SRCS lists the individual SGML files that make up the document. Changes -# to any of these files will force a rebuild -# - -# SGML content -SRCS= book.sgml -SRCS+= introduction/chapter.sgml -SRCS+= tools/chapter.sgml -SRCS+= secure/chapter.sgml -SRCS+= locking/chapter.sgml -SRCS+= sockets/chapter.sgml -SRCS+= ipv6/chapter.sgml -SRCS+= isa/chapter.sgml -SRCS+= pci/chapter.sgml -SRCS+= usb/chapter.sgml -SRCS+= scsi/chapter.sgml -SRCS+= x86/chapter.sgml -SRCS+= vm/chapter.sgml -SRCS+= dma/chapter.sgml -SRCS+= kerneldebug/chapter.sgml - -# Entities - -DOC_PREFIX?= ${.CURDIR}/../../.. -.include "${DOC_PREFIX}/share/mk/doc.project.mk" diff --git a/en_US.ISO8859-1/books/arch-handbook/book.sgml b/en_US.ISO8859-1/books/arch-handbook/book.sgml deleted file mode 100644 index 6f625557bd..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/book.sgml +++ /dev/null @@ -1,311 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/book.sgml,v 1.26 2001/09/02 03:11:08 murray Exp $ ---> - -<!DOCTYPE BOOK PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [ -<!ENTITY % bookinfo PUBLIC "-//FreeBSD//ENTITIES DocBook BookInfo Entities//EN"> -%bookinfo; -<!ENTITY % man PUBLIC "-//FreeBSD//ENTITIES DocBook Manual Page Entities//EN"> -%man; -<!ENTITY % chapters SYSTEM "chapters.ent"> %chapters; -<!ENTITY % authors PUBLIC "-//FreeBSD//ENTITIES DocBook Author Entities//EN"> %authors -<!ENTITY % mailing-lists PUBLIC "-//FreeBSD//ENTITIES DocBook Mailing List Entities//EN"> %mailing-lists; -]> - -<book> - <bookinfo> - <title>FreeBSD Developers' Handbook</title> - - <corpauthor>The FreeBSD Documentation Project</corpauthor> - - <pubdate>August 2000</pubdate> - - <copyright> - <year>2000</year> - <year>2001</year> - <holder>The FreeBSD Documentation Project</holder> - </copyright> - - &bookinfo.legalnotice; - - <abstract> - <para>Welcome to the Developers' Handbook. This manual is a - <emphasis>work in progress</emphasis> and is the work of many - individuals. Many sections do not yet exist and some of those - that do exist need to be updated. If you are interested in - helping with this project, send email to the &a.doc;.</para> - - <para>The latest version of this document is always available - from the <ulink URL="http://www.FreeBSD.org/">FreeBSD World - Wide Web server</ulink>. It may also be downloaded in a - variety of formats and compression options from the <ulink - url="ftp://ftp.FreeBSD.org/pub/FreeBSD/doc">FreeBSD FTP - server</ulink> or one of the numerous <ulink - url="http://www.freebsd.org/handbook/mirrors-ftp.html">mirror - sites</ulink>.</para> - </abstract> - </bookinfo> - - <part id="Basics"> - <title>Basics</title> - - &chap.introduction; - &chap.tools; - &chap.secure; - - </part> - - <part id="ipc"> - <title>Interprocess Communication</title> - - <chapter id="signals"> - <title>* Signals</title> - - <para>Signals, pipes, semaphores, message queues, shared memory, - ports, sockets, doors</para> - - </chapter> - - &chap.sockets; - &chap.ipv6; - - </part> - - <part id="kernel"> - <title>Kernel</title> - - <chapter id="kernelhistory"> - <title>* History of the Unix Kernel</title> - - <para>Some history of the Unix/BSD kernel, system calls, how do - processes work, blocking, scheduling, threads (kernel), - context switching, signals, interrupts, modules, etc.</para> - - <para></para> - </chapter> - - &chap.locking; - &chap.kobj; - &chap.sysinit; - &chap.vm; - &chap.dma; - &chap.kerneldebug; - - <chapter id="ufs"> - <title>* UFS</title> - - <para>UFS, FFS, Ext2FS, JFS, inodes, buffer cache, labeling, - locking, metadata, soft-updates, LFS, portalfs, procfs, - vnodes, memory sharing, memory objects, TLBs, caching</para> - - </chapter> - - <chapter id="afs"> - <title>* AFS</title> - - <para>AFS, NFS, SANs etc]</para> - - </chapter> - - <chapter id="syscons"> - <title>* Syscons</title> - - <para>Syscons, tty, PCVT, serial console, screen savers, - etc</para> - - </chapter> - - <chapter id="compatibility"> - <title>* Compatibility Layers</title> - - <sect1 id="linux"> - <title>* Linux</title> - - <para>Linux, SVR4, etc</para> - </sect1> - - </chapter> - </part> - - <part id="devicedrivers"> - <title>Device Drivers</title> - - &chap.driverbasics; - &chap.isa; - &chap.pci; - &chap.scsi; - &chap.usb; - - <chapter id="newbus"> - <title>* NewBus</title> - - <para>This chapter will talk about the FreeBSD NewBus - architecture.</para> - </chapter> - - <chapter id="oss"> - <title>* Sound subsystem</title> - - <para>OSS, waveforms, etc</para> - - </chapter> - - </part> - - <part id="architectures"> - <title>Architectures</title> - - &chap.x86; - - <chapter id="alpha"> - <title>* Alpha</title> - - <para>Talk about the architectural specifics of - FreeBSD/alpha.</para> - - <para>Explanation of allignment errors, how to fix, how to - ignore.</para> - - <para>Example assembly language code for FreeBSD/alpha.</para> - </chapter> - - <chapter id="ia64"> - <title>* IA-64</title> - - <para>Talk about the architectural specifics of - FreeBSD/ia64.</para> - - </chapter> - </part> - - <part id="appendices"> - <title>Appendices</title> - - <bibliography> - - <biblioentry id="COD" xreflabel="1"> - <authorgroup> - <author> - <firstname>Dave</firstname> - <othername role="MI">A</othername> - <surname>Patterson</surname> - </author> - <author> - <firstname>John</firstname> - <othername role="MI">L</othername> - <surname>Hennessy</surname> - </author> - </authorgroup> - <copyright><year>1998</year><holder>Morgan Kaufmann Publishers, - Inc.</holder></copyright> - <isbn>1-55860-428-6</isbn> - <publisher> - <publishername>Morgan Kaufmann Publishers, Inc.</publishername> - </publisher> - <title>Computer Organization and Design</title> - <subtitle>The Hardware / Software Interface</subtitle> - <pagenums>1-2</pagenums> - </biblioentry> - - <biblioentry xreflabel="2"> - <authorgroup> - <author> - <firstname>W.</firstname> - <othername role="Middle">Richard</othername> - <surname>Stevens</surname> - </author> - </authorgroup> - <copyright><year>1993</year><holder>Addison Wesley Longman, - Inc.</holder></copyright> - <isbn>0-201-56317-7</isbn> - <publisher> - <publishername>Addison Wesley Longman, Inc.</publishername> - </publisher> - <title>Advanced Programming in the Unix Environment</title> - <pagenums>1-2</pagenums> - </biblioentry> - - <biblioentry xreflabel="3"> - <authorgroup> - <author> - <firstname>Marshall</firstname> - <othername role="Middle">Kirk</othername> - <surname>McKusick</surname> - </author> - <author> - <firstname>Keith</firstname> - <surname>Bostic</surname> - </author> - <author> - <firstname>Michael</firstname> - <othername role="MI">J</othername> - <surname>Karels</surname> - </author> - <author> - <firstname>John</firstname> - <othername role="MI">S</othername> - <surname>Quarterman</surname> - </author> - </authorgroup> - <copyright><year>1996</year><holder>Addison-Wesley Publishing Company, - Inc.</holder></copyright> - <isbn>0-201-54979-4</isbn> - <publisher> - <publishername>Addison-Wesley Publishing Company, Inc.</publishername> - </publisher> - <title>The Design and Implementation of the 4.4 BSD Operating System</title> - <pagenums>1-2</pagenums> - </biblioentry> - - <biblioentry id="Phrack" xreflabel="4"> - <authorgroup> - <author> - <firstname>Aleph</firstname> - <surname>One</surname> - </author> - </authorgroup> - <title>Phrack 49; "Smashing the Stack for Fun and Profit"</title> - </biblioentry> - - <biblioentry id="StackGuard" xreflabel="5"> - <authorgroup> - <author> - <firstname>Chrispin</firstname> - <surname>Cowan</surname> - </author> - <author> - <firstname>Calton</firstname> - <surname>Pu</surname> - </author> - <author> - <firstname>Dave</firstname> - <surname>Maier</surname> - </author> - </authorgroup> - <title>StackGuard; Automatic Adaptive Detection and Prevention of - Buffer-Overflow Attacks</title> - </biblioentry> - - <biblioentry id="OpenBSD" xreflabel="6"> - <authorgroup> - <author> - <firstname>Todd</firstname> - <surname>Miller</surname> - </author> - <author> - <firstname>Theo</firstname> - <surname>de Raadt</surname> - </author> - </authorgroup> - <title>strlcpy and strlcat -- consistent, safe string copy and - concatenation.</title> - </biblioentry> - - </bibliography> - - &chap.index; - </part> - -</book> diff --git a/en_US.ISO8859-1/books/arch-handbook/chapters.ent b/en_US.ISO8859-1/books/arch-handbook/chapters.ent deleted file mode 100644 index 1ef9ebe938..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/chapters.ent +++ /dev/null @@ -1,65 +0,0 @@ -<!-- - Creates entities for each chapter in the FreeBSD Developer's - Handbook. Each entity is named chap.foo, where foo is the value - of the id attribute on that chapter, and corresponds to the name of - the directory in which that chapter's .sgml file is stored. - - Chapters should be listed in the order in which they are referenced. - - $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/chapters.ent,v 1.11 2001/09/02 03:11:08 murray Exp $ ---> - -<!-- Part one --> -<!ENTITY chap.introduction SYSTEM "introduction/chapter.sgml"> -<!ENTITY chap.tools SYSTEM "tools/chapter.sgml"> -<!ENTITY chap.secure SYSTEM "secure/chapter.sgml"> - -<!-- Part two --> -<!ENTITY chap.kobj SYSTEM "kobj/chapter.sgml"> -<!ENTITY chap.sysinit SYSTEM "sysinit/chapter.sgml"> -<!ENTITY chap.locking SYSTEM "locking/chapter.sgml"> - -<!-- Part three --> -<!ENTITY chap.vm SYSTEM "vm/chapter.sgml"> -<!ENTITY chap.dma SYSTEM "dma/chapter.sgml"> - -<!-- Part four --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part five --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part six --> -<!ENTITY chap.sockets SYSTEM "sockets/chapter.sgml"> -<!ENTITY chap.ipv6 SYSTEM "ipv6/chapter.sgml"> - -<!-- Part seven --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part eight --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part nine --> -<!-- No significant material yet, still in book.sgml --> - -<!ENTITY chap.kerneldebug SYSTEM "kerneldebug/chapter.sgml"> - -<!-- Part ten --> -<!ENTITY chap.driverbasics SYSTEM "driverbasics/chapter.sgml"> -<!ENTITY chap.isa SYSTEM "isa/chapter.sgml"> -<!ENTITY chap.pci SYSTEM "pci/chapter.sgml"> -<!ENTITY chap.scsi SYSTEM "scsi/chapter.sgml"> -<!ENTITY chap.usb SYSTEM "usb/chapter.sgml"> - -<!-- Part eleven --> -<!ENTITY chap.x86 SYSTEM "x86/chapter.sgml"> - -<!-- Part twelve --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part thirteen --> -<!-- No significant material yet, still in book.sgml --> - -<!-- Part fourteen (appendices) --> -<!ENTITY chap.bibliography SYSTEM "bibliography/chapter.sgml"> -<!ENTITY chap.index SYSTEM "index.sgml"> diff --git a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml deleted file mode 100644 index a65ec54238..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml +++ /dev/null @@ -1,391 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml,v 1.8 2001/07/19 10:37:35 dd Exp $ ---> - -<chapter id="driverbasics"> - <title>Writing FreeBSD Device Drivers</title> - - <para>This chapter was written by &a.murray; with selections from a - variety of sources including the intro(4) man page by - &a.joerg;.</para> - - <sect1> - <title>Introduction</title> - <para>This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic kernel - linker facility `kld'.</para> - - <para>Most devices in a Unix-like operating system are accessed - through device-nodes, sometimes also called special files. - These files are usually located under the directory - <filename>/dev</filename> in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must be - created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running <command>MAKEDEV</command>.</para> - - <para>Device drivers can roughly be broken down into two - categories; character and network device drivers.</para> - - </sect1> - - <sect1> - <title>Dynamic Kernel Linker Facility - KLD</title> - - <para>The kld interface allows system administrators to - dynamically add and remove functionality from a running system. - This allows device driver writers to load their new changes into - a running kernel without constantly rebooting to test - changes.</para> - - <para>The kld interface is used through the following - administrator commands : - - <itemizedlist> - <listitem><simpara><command>kldload</command> - loads a new kernel - module</simpara></listitem> - <listitem><simpara><command>kldunload</command> - unloads a kernel - module</simpara></listitem> - <listitem><simpara><command>kldstat</command> - lists the currently loadded - modules</simpara></listitem> - </itemizedlist> - </para> - - <para>Skeleton Layout of a kernel module</para> - -<programlisting>/* - * KLD Skeleton - * Inspired by Andrew Reiter's Daemonnews article - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ - -/* - * Load handler that deals with the loading and unloading of a KLD. - */ - -static int -skel_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - uprintf("Skeleton KLD loaded.\n"); - break; - case MOD_UNLOAD: - uprintf("Skeleton KLD unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -/* Declare this module to the rest of the kernel */ - -static moduledata_t skel_mod = { - "skel", - skel_loader, - NULL -}; - -DECLARE_MODULE(skeleton, skel_mod, SI_SUB_KLD, SI_ORDER_ANY);</programlisting> - - - <sect2> - <title>Makefile</title> - - <para>FreeBSD provides a makefile include that you can use to - quickly compile your kernel addition.</para> - - <programlisting>SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk></programlisting> - - <para>Simply running <command>make</command> with this makefile - will create a file <filename>skeleton.ko</filename> that can - be loaded into your system by typing : -<screen> &prompt.root - kldload -v ./skeleton.ko</screen> - </para> - </sect2> - </sect1> - - <sect1> - <title>Accessing a device driver</title> - - <para>Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The <command>/dev/MAKEDEV</command> - script makes most of the device nodes for your system but if you - are doing your own driver development it may be necessary to - create your own device nodes with <command>mknod</command> - </para> - - <sect2> - <title>Creating static device nodes</title> - - <para>The <command>mknod</command> command requires four - arguments to create a device node. You must specify the name - of this device node, the type of device, the major number of - the device, and the minor number of the device.</para> - </sect2> - - <sect2> - <title>Dynamic device nodes</title> - - <para>The device filesystem, or devfs, provides access to the - kernel's device namespace in the global filesystem namespace. - This eliminates the problems of potentially having a device - driver without a static device node, or a device node without - an installed device driver. Devfs is still a work in - progress, but it is already working quite nice.</para> - </sect2> - - </sect1> - - <sect1> - <title>Character Devices</title> - - <para>A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples in - the source tree.</para> - - <para>This simple example pseudo-device remembers whatever values - you write to it and can then supply them back to you when you - read from it.</para> - - <programlisting>/* - * Simple `echo' pseudo-device KLD - * - * Murray Stokely - */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> - -#define BUFFERSIZE 256 - -/* Function prototypes */ -d_open_t echo_open; -d_close_t echo_close; -d_read_t echo_read; -d_write_t echo_write; - -/* Character device entry points */ -static struct cdevsw echo_cdevsw = { - echo_open, - echo_close, - echo_read, - echo_write, - noioctl, - nopoll, - nommap, - nostrategy, - "echo", - 33, /* reserved for lkms - /usr/src/sys/conf/majors */ - nodump, - nopsize, - D_TTY, - -1 -}; - -typedef struct s_echo { - char msg[BUFFERSIZE]; - int len; -} t_echo; - -/* vars */ -static dev_t sdev; -static int len; -static int count; -static t_echo *echomsg; - -MALLOC_DECLARE(M_ECHOBUF); -MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); - -/* - * This function acts is called by the kld[un]load(2) system calls to - * determine what actions to take when a module is loaded or unloaded. - */ - -static int -echo_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - sdev = make_dev(<literal>&</literal>echo_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "echo"); - /* kmalloc memory for use by this driver */ - /* malloc(256,M_ECHOBUF,M_WAITOK); */ - MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); - printf("Echo device loaded.\n"); - break; - case MOD_UNLOAD: - destroy_dev(sdev); - FREE(echomsg,M_ECHOBUF); - printf("Echo device unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -int -echo_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int err = 0; - - uprintf("Opened device \"echo\" successfully.\n"); - return(err); -} - -int -echo_close(dev_t dev, int fflag, int devtype, struct proc *p) -{ - uprintf("Closing device \"echo.\"\n"); - return(0); -} - -/* - * The read function just takes the buf that was saved via - * echo_write() and returns it to userland for accessing. - * uio(9) - */ - -int -echo_read(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - int amt; - - /* How big is this read operation? Either as big as the user wants, - or as big as the remaining data */ - amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); - if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { - uprintf("uiomove failed!\n"); - } - - return err; -} - -/* - * echo_write takes in a character string and saves it - * to buf for later accessing. - */ - -int -echo_write(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - /* Copy the string in from user memory to kernel memory */ - err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); - - /* Now we need to null terminate */ - *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; - /* Record the length */ - echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); - - if (err != 0) { - uprintf("Write failed: bad address!\n"); - } - - count++; - return(err); -} - -DEV_MODULE(echo,echo_loader,NULL);</programlisting> - - <para>To install this driver you will first need to make a node on - your filesystem with a command such as : </para> - - <screen>&prompt.root mknod /dev/echo c 33 0</screen> - - <para>With this driver loaded you should now be able to type - something like :</para> - - <screen>&prompt.root echo -n "Test Data" > /dev/echo -&prompt.root cat /dev/echo -Test Data</screen> - - <para>Real hardware devices in the next chapter..</para> - - <para>Additional Resources - <itemizedlist> - <listitem><simpara><ulink - url="http://www.daemonnews.org/200010/blueprints.html">Dynamic - Kernel Linker (KLD) Facility Programming Tutorial</ulink> - - <ulink url="http://www.daemonnews.org">Daemonnews</ulink> October 2000</simpara></listitem> - <listitem><simpara><ulink - url="http://www.daemonnews.org/200007/newbus-intro.html">How - to Write Kernel Drivers with NEWBUS</ulink> - <ulink - url="http://www.daemonnews.org">Daemonnews</ulink> July - 2000</simpara></listitem> - </itemizedlist> - </para> - </sect1> - - <sect1> - <title>Network Drivers</title> - - <para>Drivers for network devices do not use device nodes in order - to be accessed. Their selection is based on other decisions - made inside the kernel and instead of calling open(), use of a - network device is generally introduced by using the system call - socket(2).</para> - - <para>man ifnet(), loopback device, Bill Paul's drivers, - etc..</para> - - </sect1> - -</chapter> - -<!-- - Local Variables: - mode: sgml - sgml-declaration: "../chapter.decl" - sgml-indent-data: t - sgml-omittag: nil - sgml-always-quote-attributes: t - sgml-parent-document: ("../book.sgml" "part" "chapter") - End: ---> diff --git a/en_US.ISO8859-1/books/arch-handbook/isa/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/isa/chapter.sgml deleted file mode 100644 index 96f68a88c5..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/isa/chapter.sgml +++ /dev/null @@ -1,2479 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/isa/chapter.sgml,v 1.1 2001/05/02 01:56:01 murray Exp $ ---> - -<chapter id="isa-driver"> - <title>ISA device drivers</title> - - <para> - <emphasis> - This chapter was written by &a.babkin; Modifications for the - handbook made by &a.murray;, &a.wylie;, and &a.logo;. - </emphasis> - </para> - - <sect1> - <title>Synopsis</title> - - <para>This chapter introduces the issues relevant to writing a - driver for an ISA device. The pseudo-code presented here is - rather detailed and reminiscent of the real code but is still - only pseudo-code. It avoids the details irrelevant to the - subject of the discussion. The real-life examples can be found - in the source code of real drivers. In particular the drivers - "ep" and "aha" are good sources of information.</para> - </sect1> - - <sect1> - <title>Basic information</title> - - <para>A typical ISA driver would need the following include - files:</para> - -<programlisting>#include <sys/module.h> -#include <sys/bus.h> -#include <machine/bus.h> -#include <machine/resource.h> -#include <sys/rman.h> - -#include <isa/isavar.h> -#include <isa/pnpvar.h></programlisting> - - <para>They describe the things specific to the ISA and generic - bus subsystem.</para> - - <para>The bus subsystem is implemented in an object-oriented - fashion, its main structures are accessed by associated method - functions.</para> - - <para>The list of bus methods implemented by an ISA driver is like - one for any other bus. For a hypothetical driver named "xxx" - they would be:</para> - - <itemizedlist> - <listitem> - <para><function>static void xxx_isa_identify (driver_t *, - device_t);</function> Normally used for bus drivers, not - device drivers. But for ISA devices this method may have - special use: if the device provides some device-specific - (non-PnP) way to auto-detect devices this routine may - implement it.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_probe (device_t - dev);</function> Probe for a device at a known (or PnP) - location. This routine can also accommodate device-specific - auto-detection of parameters for partially configured - devices.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_attach (device_t - dev);</function> Attach and initialize device.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_detach (device_t - dev);</function> Detach device before unloading the driver - module.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_shutdown (device_t - dev);</function> Execute shutdown of the device before - system shutdown.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_suspend (device_t - dev);</function> Suspend the device before the system goes - to the power-save state. May also abort transition to the - power-save state.</para> - </listitem> - - <listitem> - <para><function>static int xxx_isa_resume (device_t - dev);</function> Resume the device activity after return - from power-save state.</para> - </listitem> - - </itemizedlist> - - <para><function>xxx_isa_probe()</function> and - <function>xxx_isa_attach()</function> are mandatory, the rest of - the routines are optional, depending on the device's - needs.</para> - - <para>The driver is linked to the system with the following set of - descriptions.</para> - -<programlisting> /* table of supported bus methods */ - static device_method_t xxx_isa_methods[] = { - /* list all the bus method functions supported by the driver */ - /* omit the unsupported methods */ - DEVMETHOD(device_identify, xxx_isa_identify), - DEVMETHOD(device_probe, xxx_isa_probe), - DEVMETHOD(device_attach, xxx_isa_attach), - DEVMETHOD(device_detach, xxx_isa_detach), - DEVMETHOD(device_shutdown, xxx_isa_shutdown), - DEVMETHOD(device_suspend, xxx_isa_suspend), - DEVMETHOD(device_resume, xxx_isa_resume), - - { 0, 0 } - }; - - static driver_t xxx_isa_driver = { - "xxx", - xxx_isa_methods, - sizeof(struct xxx_softc), - }; - - - static devclass_t xxx_devclass; - - DRIVER_MODULE(xxx, isa, xxx_isa_driver, xxx_devclass, - load_function, load_argument);</programlisting> - - <para>Here struct <structname>xxx_softc</structname> is a - device-specific structure that contains private driver data - and descriptors for the driver's resources. The bus code - automatically allocates one softc descriptor per device as - needed.</para> - - <para>If the driver is implemented as a loadable module then - <function>load_function()</function> is called to do - driver-specific initialization or clean-up when the driver is - loaded or unloaded and load_argument is passed as one of its - arguments. If the driver does not support dynamic loading (in - other words it must always be linked into kernel) then these - values should be set to 0 and the last definition would look - like:</para> - - <programlisting> DRIVER_MODULE(xxx, isa, xxx_isa_driver, - xxx_devclass, 0, 0);</programlisting> - - <para>If the driver is for a device which supports PnP then a - table of supported PnP IDs must be defined. The table - consists of a list of PnP IDs supported by this driver and - human-readable descriptions of the hardware types and models - having these IDs. It looks like:</para> - -<programlisting> static struct isa_pnp_id xxx_pnp_ids[] = { - /* a line for each supported PnP ID */ - { 0x12345678, "Our device model 1234A" }, - { 0x12345679, "Our device model 1234B" }, - { 0, NULL }, /* end of table */ - };</programlisting> - - <para>If the driver does not support PnP devices it still needs - an empty PnP ID table, like:</para> - -<programlisting> static struct isa_pnp_id xxx_pnp_ids[] = { - { 0, NULL }, /* end of table */ - };</programlisting> - - </sect1> - - <sect1> - <title>Device_t pointer</title> - - <para><structname>Device_t</structname> is the pointer type for - the device structure. Here we consider only the methods - interesting from the device driver writer's standpoint. The - methods to manipulate values in the device structure - are:</para> - - <itemizedlist> - - <listitem><para><function>device_t - device_get_parent(dev)</function> Get the parent bus of a - device.</para></listitem> - - <listitem><para><function>driver_t - device_get_driver(dev)</function> Get pointer to its driver - structure.</para></listitem> - - <listitem><para><function>char - *device_get_name(dev)</function> Get the driver name, such - as "xxx" for our example.</para></listitem> - - <listitem><para><function>int device_get_unit(dev)</function> - Get the unit number (units are numbered from 0 for the - devices associated with each driver).</para></listitem> - - <listitem><para><function>char - *device_get_nameunit(dev)</function> Get the device name - including the unit number, such as "xxx0" , "xxx1" and so - on.</para></listitem> - - <listitem><para><function>char - *device_get_desc(dev)</function> Get the device - description. Normally it describes the exact model of device - in human-readable form.</para></listitem> - - <listitem><para><function>device_set_desc(dev, - desc)</function> Set the description. This makes the device - description point to the string desc which may not be - deallocated or changed after that.</para></listitem> - - <listitem><para><function>device_set_desc_copy(dev, - desc)</function> Set the description. The description is - copied into an internal dynamically allocated buffer, so the - string desc may be changed afterwards without adverse - effects.</para></listitem> - - <listitem><para><function>void - *device_get_softc(dev)</function> Get pointer to the device - descriptor (struct <structname>xxx_softc</structname>) - associated with this device.</para></listitem> - - <listitem><para><function>u_int32_t - device_get_flags(dev)</function> Get the flags specified for - the device in the configuration file.</para></listitem> - - </itemizedlist> - - <para>A convenience function <function>device_printf(dev, fmt, - ...)</function> may be used to print the messages from the - device driver. It automatically prepends the unitname and - colon to the message.</para> - - <para>The device_t methods are implemented in the file - kern/bus_subr.c.</para> - - </sect1> - - <sect1> - <title>Config file and the order of identifying and probing - during auto-configuration</title> - - <para>The ISA devices are described in the kernel config file - like:</para> - - <programlisting>device xxx0 at isa? port 0x300 irq 10 drq 5 - iomem 0xd0000 flags 0x1 sensitive</programlisting> - - <para>The values of port, IRQ and so on are converted to the - resource values associated with the device. They are optional, - depending on the device needs and abilities for - auto-configuration. For example, some devices don't need DRQ - at all and some allow the driver to read the IRQ setting from - the device configuration ports. If a machine has multiple ISA - buses the exact bus may be specified in the configuration - line, like "isa0" or "isa1", otherwise the device would be - searched for on all the ISA buses.</para> - - <para>"sensitive" is a resource requesting that this device must - be probed before all non-sensitive devices. It is supported - but does not seem to be used in any current driver.</para> - - <para>For legacy ISA devices in many cases the drivers are still - able to detect the configuration parameters. But each device - to be configured in the system must have a config line. If two - devices of some type are installed in the system but there is - only one configuration line for the corresponding driver, ie: - <programlisting>device xxx0 at isa?</programlisting> then only - one device will be configured.</para> - - <para>But for the devices supporting automatic identification by - the means of Plug-n-Play or some proprietary protocol one - configuration line is enough to configure all the devices in - the system, like the one above or just simply:</para> - - <programlisting>device xxx at isa?</programlisting> - - <para>If a driver supports both auto-identified and legacy - devices and both kinds are installed at once in one machine - then it's enough to describe in the config file the legacy - devices only. The auto-identified devices will be added - automatically.</para> - - <para>When an ISA bus is auto-configured the events happen as - follows:</para> - - <para>All the drivers' identify routines (including the PnP - identify routine which identifies all the PnP devices) are - called in random order. As they identify the devices they add - them to the list on the ISA bus. Normally the drivers' - identify routines associate their drivers with the new - devices. The PnP identify routine does not know about the - other drivers yet so it does not associate any with the new - devices it adds.</para> - - <para>The PnP devices are put to sleep using the PnP protocol to - prevent them from being probed as legacy devices.</para> - - <para>The probe routines of non-PnP devices marked as - "sensitive" are called. If probe for a device went - successfully, the attach routine is called for it.</para> - - <para>The probe and attach routines of all non-PNP devices are - called likewise.</para> - - <para>The PnP devices are brought back from the sleep state and - assigned the resources they request: I/O and memory address - ranges, IRQs and DRQs, all of them not conflicting with the - attached legacy devices.</para> - - <para>Then for each PnP device the probe routines of all the - present ISA drivers are called. The first one that claims the - device gets attached. It is possible that multiple drivers - would claim the device with different priority, the - highest-priority driver wins. The probe routines must call - <function>ISA_PNP_PROBE()</function> to compare the actual PnP - ID with the list of the IDs supported by the driver and if the - ID is not in the table return failure. That means that - absolutely every driver, even the ones not supporting any PnP - devices must call <function>ISA_PNP_PROBE()</function>, at - least with an empty PnP ID table to return failure on unknown - PnP devices.</para> - - <para>The probe routine returns a positive value (the error - code) on error, zero or negative value on success.</para> - - <para>The negative return values are used when a PnP device - supports multiple interfaces. For example, an older - compatibility interface and a newer advanced interface which - are supported by different drivers. Then both drivers would - detect the device. The driver which returns a higher value in - the probe routine takes precedence (in other words, the driver - returning 0 has highest precedence, returning -1 is next, - returning -2 is after it and so on). In result the devices - which support only the old interface will be handled by the - old driver (which should return -1 from the probe routine) - while the devices supporting the new interface as well will be - handled by the new driver (which should return 0 from the - probe routine). If multiple drivers return the same value then - the one called first wins. So if a driver returns value 0 it - may be sure that it won the priority arbitration.</para> - - <para>The device-specific identify routines can also assign not - a driver but a class of drivers to the device. Then all the - drivers in the class are probed for this device, like the case - with PnP. This feature is not implemented in any existing - driver and is not considered further in this document.</para> - - <para>Because the PnP devices are disabled when probing the - legacy devices they will not be attached twice (once as legacy - and once as PnP). But in case of device-dependent identify - routines it's the responsibility of the driver to make sure - that the same device won't be attached by the driver twice: - once as legacy user-configured and once as - auto-identified.</para> - - <para>Another practical consequence for the auto-identified - devices (both PnP and device-specific) is that the flags can - not be passed to them from the kernel configuration file. So - they must either not use the flags at all or use the flags - from the device unit 0 for all the auto-identified devices or - use the sysctl interface instead of flags.</para> - - <para>Other unusual configurations may be accommodated by - accessing the configuration resources directly with functions - of families <function>resource_query_*()</function> and - <function>resource_*_value()</function>. Their implementations - are located in kern/subr_bus.h. The old IDE disk driver - i386/isa/wd.c contains examples of such use. But the standard - means of configuration must always be preferred. Leave parsing - the configuration resources to the bus configuration - code.</para> - - </sect1> - - <sect1> - <title>Resources</title> - - <para>The information that a user enters into the kernel - configuration file is processed and passed to the kernel as - configuration resources. This information is parsed by the bus - configuration code and transformed into a value of structure - device_t and the bus resources associated with it. The drivers - may access the configuration resources directly using - functions resource_* for more complex cases of - configuration. But generally it's not needed nor recommended, - so this issue is not discussed further.</para> - - <para>The bus resources are associated with each device. They - are identified by type and number within the type. For the ISA - bus the following types are defined:</para> - - <itemizedlist> - <listitem> - <para><emphasis>SYS_RES_IRQ</emphasis> - interrupt - number</para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_DRQ</emphasis> - ISA DMA channel - number</para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_MEMORY</emphasis> - range of - device memory mapped into the system memory space - </para> - </listitem> - - <listitem> - <para><emphasis>SYS_RES_IOPORT</emphasis> - range of - device I/O registers</para> - </listitem> - </itemizedlist> - - <para>The enumeration within types starts from 0, so if a device - has two memory regions if would have resources of type - SYS_RES_MEMORY numbered 0 and 1. The resource type has - nothing to do with the C language type, all the resource - values have the C language type "unsigned long" and must be - cast as necessary. The resource numbers don't have to be - contiguous although for ISA they normally would be. The - permitted resource numbers for ISA devices are:</para> - - <programlisting> IRQ: 0-1 - DRQ: 0-1 - MEMORY: 0-3 - IOPORT: 0-7</programlisting> - - <para>All the resources are represented as ranges, with a start - value and count. For IRQ and DRQ resources the count would be - normally equal to 1. The values for memory refer to the - physical addresses.</para> - - <para>Three types of activities can be performed on - resources:</para> - - <itemizedlist> - <listitem><para>set/get</para></listitem> - <listitem><para>allocate/release</para></listitem> - <listitem><para>activate/deactivate</para></listitem> - </itemizedlist> - - <para>Setting sets the range used by the resource. Allocation - reserves the requested range that no other driver would be - able to reserve it (and checking that no other driver reserved - this range already). Activation makes the resource accessible - to the driver doing whatever is necessary for that (for - example, for memory it would be mapping into the kernel - virtual address space).</para> - - <para>The functions to manipulate resources are:</para> - - <itemizedlist> - <listitem> - <para><function>int bus_set_resource(device_t dev, int type, - int rid, u_long start, u_long count)</function></para> - - <para>Set a range for a resource. Returns 0 if successful, - error code otherwise. Normally the only reason this - function would return an error is value of type, rid, - start or count out of permitted range.</para> - - <itemizedlist> - <listitem> - <para> dev - driver's device</para> - </listitem> - <listitem> - <para> type - type of resource, SYS_RES_* </para> - </listitem> - <listitem> - <para> rid - resource number (ID) within type </para> - </listitem> - <listitem> - <para> start, count - resource range </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> - <para><function>int bus_get_resource(device_t dev, int type, - int rid, u_long *startp, u_long *countp)</function></para> - - <para>Get the range of resource. Returns 0 if successful, - error code if the resource is not defined yet.</para> - </listitem> - - <listitem> - <para><function>u_long bus_get_resource_start(device_t dev, - int type, int rid) u_long bus_get_resource_count (device_t - dev, int type, int rid)</function></para> - - <para>Convenience functions to get only the start or - count. Return 0 in case of error, so if the resource start - has 0 among the legitimate values it would be impossible - to tell if the value is 0 or an error occurred. Luckily, - no ISA resources for add-on drivers may have a start value - equal 0.</para> - </listitem> - - <listitem> - <para><function>void bus_delete_resource(device_t dev, int - type, int rid)</function></para> - <para> Delete a resource, make it undefined.</para> - </listitem> - - <listitem> - <para><function>struct resource * - bus_alloc_resource(device_t dev, int type, int *rid, - u_long start, u_long end, u_long count, u_int - flags)</function></para> - - <para>Allocate a resource as a range of count values not - allocated by anyone else, somewhere between start and - end. Alas, alignment is not supported. If the resource - was not set yet it's automatically created. The special - values of start 0 and end ~0 (all ones) means that the - fixed values previously set by - <function>bus_set_resource()</function> must be used - instead: start and count as themselves and - end=(start+count), in this case if the resource was not - defined before then an error is returned. Although rid is - passed by reference it's not set anywhere by the resource - allocation code of the ISA bus. (The other buses may use a - different approach and modify it).</para> - </listitem> - </itemizedlist> - - <para>Flags are a bitmap, the flags interesting for the caller - are:</para> - - <itemizedlist> - <listitem> - <para><emphasis>RF_ACTIVE</emphasis> - causes the resource - to be automatically activated after allocation.</para> - </listitem> - - <listitem> - <para><emphasis>RF_SHAREABLE</emphasis> - resource may be - shared at the same time by multiple drivers.</para> - </listitem> - - <listitem> - <para><emphasis>RF_TIMESHARE</emphasis> - resource may be - time-shared by multiple drivers, i.e. allocated at the - same time by many but activated only by one at any given - moment of time.</para> - </listitem> -<!-- XXXDONT KNOW IT THESE SHOULD BE TWO SEPERATE LISTS OR NOT --> - <listitem> - <para>Returns 0 on error. The allocated values may be - obtained from the returned handle using methods - <function>rhand_*()</function>.</para> - </listitem> - <listitem> - <para><function>int bus_release_resource(device_t dev, int - type, int rid, struct resource *r)</function></para> - </listitem> - - <listitem> - <para>Release the resource, r is the handle returned by - <function>bus_alloc_resource()</function>. Returns 0 on - success, error code otherwise.</para> - </listitem> - - <listitem> - <para><function>int bus_activate_resource(device_t dev, int - type, int rid, struct resource *r)</function> - <function>int bus_deactivate_resource(device_t dev, int - type, int rid, struct resource *r)</function></para> - </listitem> - - <listitem> - <para>Activate or deactivate resource. Return 0 on success, - error code otherwise. If the resource is time-shared and - currently activated by another driver then EBUSY is - returned.</para> - </listitem> - - <listitem> - <para><function>int bus_setup_intr(device_t dev, struct - resource *r, int flags, driver_intr_t *handler, void *arg, - void **cookiep)</function> <function>int - bus_teardown_intr(device_t dev, struct resource *r, void - *cookie)</function></para> - </listitem> - - <listitem> - <para>Associate or de-associate the interrupt handler with a - device. Return 0 on success, error code otherwise.</para> - </listitem> - - <listitem> - <para>r - the activated resource handler describing the - IRQ</para> - <para>flags - the interrupt priority level, one of:</para> - - <itemizedlist> - <listitem> - <para><function>INTR_TYPE_TTY</function> - terminals and - other likewise character-type devices. To mask them - use <function>spltty()</function>.</para> - </listitem> - <listitem> - <para><function>(INTR_TYPE_TTY | - INTR_TYPE_FAST)</function> - terminal type devices - with small input buffer, critical to the data loss on - input (such as the old-fashioned serial ports). To - mask them use <function>spltty()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_BIO</function> - block-type - devices, except those on the CAM controllers. To mask - them use <function>splbio()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_CAM</function> - CAM (Common - Access Method) bus controllers. To mask them use - <function>splcam()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_NET</function> - network - interface controllers. To mask them use - <function>splimp()</function>.</para> - </listitem> - <listitem> - <para><function>INTR_TYPE_MISC</function> - - miscellaneous devices. There is no other way to mask - them than by <function>splhigh()</function> which - masks all interrupts.</para> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> - - <para>When an interrupt handler executes all the other - interrupts matching its priority level will be masked. The - only exception is the MISC level for which no other interrupts - are masked and which is not masked by any other - interrupt.</para> - - <itemizedlist> - <listitem> - <para><emphasis>handler</emphasis> - pointer to the handler - function, the type driver_intr_t is defined as "void - driver_intr_t(void *)"</para> - </listitem> - <listitem> - <para><emphasis>arg</emphasis> - the argument passed to the - handler to identify this particular device. It is cast - from void* to any real type by the handler. The old - convention for the ISA interrupt handlers was to use the - unit number as argument, the new (recommended) convention - is using a pointer to the device softc structure.</para> - </listitem> - <listitem> - <para><emphasis>cookie[p]</emphasis> - the value received - from <function>setup()</function> is used to identify the - handler when passed to - <function>teardown()</function></para> - </listitem> - </itemizedlist> - - <para>A number of methods is defined to operate on the resource - handlers (struct resource *). Those of interest to the device - driver writers are:</para> - - <itemizedlist> - <listitem> - <para><function>u_long rman_get_start(r) u_long - rman_get_end(r)</function> Get the start and end of - allocated resource range.</para> - </listitem> - <listitem> - <para><function>void *rman_get_virtual(r)</function> Get - the virtual address of activated memory resource.</para> - </listitem> - </itemizedlist> - - </sect1> - - <sect1> - <title>Bus memory mapping</title> - - <para>In many cases data is exchanged between the driver and the - device through the memory. Two variants are possible:</para> - - <para>(a) memory is located on the device card</para> - <para>(b) memory is the main memory of computer</para> - - <para>In the case (a) the driver always copies the data back and - forth between the on-card memory and the main memory as - necessary. To map the on-card memory into the kernel virtual - address space the physical address and length of the on-card - memory must be defined as a SYS_RES_MEMORY resource. That - resource can then be allocated and activated, and its virtual - address obtained using - <function>rman_get_virtual()</function>. The older drivers - used the function <function>pmap_mapdev()</function> for this - purpose, which should not be used directly any more. Now it's - one of the internal steps of resource activation.</para> - - <para>Most of the ISA cards will have their memory configured - for physical location somewhere in range 640KB-1MB. Some of - the ISA cards require larger memory ranges which should be - placed somewhere under 16MB (because of the 24-bit address - limitation on the ISA bus). In that case if the machine has - more memory than the start address of the device memory (in - other words, they overlap) a memory hole must be configured at - the address range used by devices. Many BIOSes allow to - configure a memory hole of 1MB starting at 14MB or - 15MB. FreeBSD can handle the memory holes properly if the BIOS - reports them properly (old BIOSes may have this feature - broken).</para> - - <para>In the case (b) just the address of the data is sent to - the device, and the device uses DMA to actually access the - data in the main memory. Two limitations are present: First, - ISA cards can only access memory below 16MB. Second, the - contiguous pages in virtual address space may not be - contiguous in physical address space, so the device may have - to do scatter/gather operations. The bus subsystem provides - ready solutions for some of these problems, the rest has to be - done by the drivers themselves.</para> - - <para>Two structures are used for DMA memory allocation, - bus_dma_tag_t and bus_dmamap_t. Tag describes the properties - required for the DMA memory. Map represents a memory block - allocated according to these properties. Multiple maps may be - associated with the same tag.</para> - - <para>Tags are organized into a tree-like hierarchy with - inheritance of the properties. A child tag inherits all the - requirements of its parent tag or may make them more strict - but never more loose.</para> - - <para>Normally one top-level tag (with no parent) is created for - each device unit. If multiple memory areas with different - requirements are needed for each device then a tag for each of - them may be created as a child of the parent tag.</para> - - <para>The tags can be used to create a map in two ways.</para> - - <para>First, a chunk of contiguous memory conformant with the - tag requirements may be allocated (and later may be - freed). This is normally used to allocate relatively - long-living areas of memory for communication with the - device. Loading of such memory into a map is trivial: it's - always considered as one chunk in the appropriate physical - memory range.</para> - - <para>Second, an arbitrary area of virtual memory may be loaded - into a map. Each page of this memory will be checked for - conformance to the map requirement. If it conforms then it's - left at it's original location. If it is not then a fresh - conformant "bounce page" is allocated and used as intermediate - storage. When writing the data from the non-conformant - original pages they will be copied to their bounce pages first - and then transferred from the bounce pages to the device. When - reading the data would go from the device to the bounce pages - and then copied to their non-conformant original pages. The - process of copying between the original and bounce pages is - called synchronization. This is normally used on per-transfer - basis: buffer for each transfer would be loaded, transfer done - and buffer unloaded.</para> - - <para>The functions working on the DMA memory are:</para> - - <itemizedlist> - <listitem> - <para><function>int bus_dma_tag_create(bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, bus_addr_t - lowaddr, bus_addr_t highaddr, bus_dma_filter_t *filter, void - *filterarg, bus_size_t maxsize, int nsegments, bus_size_t - maxsegsz, int flags, bus_dma_tag_t *dmat)</function></para> - - <para>Create a new tag. Returns 0 on success, the error code - otherwise.</para> - - <itemizedlist> - <listitem> - <para><emphasis>parent</emphasis> - parent tag, or NULL to - create a top-level tag <emphasis>alignment</emphasis> - - required physical alignment of the memory area to be - allocated for this tag. Use value 1 for "no specific - alignment". Applies only to the future - <function>bus_dmamem_alloc()</function> but not - <function>bus_dmamap_create()</function> calls. - <emphasis>boundary</emphasis> - physical address - boundary that must not be crossed when allocating the - memory. Use value 0 for "no boundary". Applies only to - the future <function>bus_dmamem_alloc()</function> but - not <function>bus_dmamap_create()</function> calls. - Must be power of 2. If the memory is planned to be used - in non-cascaded DMA mode (i.e. the DMA addresses will be - supplied not by the device itself but by the ISA DMA - controller) then the boundary must be no larger than - 64KB (64*1024) due to the limitations of the DMA - hardware.</para> - </listitem> - - <listitem> - <para><emphasis>lowaddr, highaddr</emphasis> - the names - are slighlty misleading; these values are used to limit - the permitted range of physical addresses used to - allocate the memory. The exact meaning varies depending - on the planned future use:</para> - - <itemizedlist> - <listitem> - <para>For <function>bus_dmamem_alloc()</function> all - the addresses from 0 to lowaddr-1 are considered - permitted, the higher ones are forbidden.</para> - </listitem> - - <listitem> - <para>For <function>bus_dmamap_create()</function> all - the addresses outside the inclusive range [lowaddr; - highaddr] are considered accessible. The addresses - of pages inside the range are passed to the filter - function which decides if they are accessible. If no - filter function is supplied then all the range is - considered unaccessible.</para> - </listitem> - - <listitem> - <para>For the ISA devices the normal values (with no - filter function) are:</para> - <para>lowaddr = BUS_SPACE_MAXADDR_24BIT</para> - <para>highaddr = BUS_SPACE_MAXADDR</para> - </listitem> - </itemizedlist> - - </listitem> - - <listitem> - <para><emphasis>filter, filterarg</emphasis> - the filter - function and its argument. If NULL is passed for filter - then the whole range [lowaddr, highaddr] is considered - unaccessible when doing - <function>bus_dmamap_create()</function>. Otherwise the - physical address of each attempted page in range - [lowaddr; highaddr] is passed to the filter function - which decides if it is accessible. The prototype of the - filter function is: <function>int filterfunc(void *arg, - bus_addr_t paddr)</function> It must return 0 if the - page is accessible, non-zero otherwise.</para> - </listitem> - - <listitem> - <para><emphasis>maxsize</emphasis> - the maximal size of - memory (in bytes) that may be allocated through this - tag. In case it's difficult to estimate or could be - arbitrarily big, the value for ISA devices would be - BUS_SPACE_MAXSIZE_24BIT.</para> - </listitem> - - <listitem> - <para><emphasis>nsegments</emphasis> - maximal number of - scatter-gather segments supported by the device. If - unrestricted then the value BUS_SPACE_UNRESTRICTED - should be used. This value is recommended for the parent - tags, the actual restrictions would then be specified - for the descendant tags. Tags with nsegments equal to - BUS_SPACE_UNRESTRICTED may not be used to actually load - maps, they may be used only as parent tags. The - practical limit for nsegments seems to be about 250-300, - higher values will cause kernel stack overflow. But - anyway the hardware normally can't support that many - scatter-gather buffers.</para> - </listitem> - - <listitem> - <para><emphasis>maxsegsz</emphasis> - maximal size of a - scatter-gather segment supported by the device. The - maximal value for ISA device would be - BUS_SPACE_MAXSIZE_24BIT.</para> - </listitem> - - <listitem> - <para><emphasis>flags</emphasis> - a bitmap of flags. The - only interesting flags are:</para> - - <itemizedlist> - <listitem> - <para><emphasis>BUS_DMA_ALLOCNOW</emphasis> - requests - to allocate all the potentially needed bounce pages - when creating the tag</para> - </listitem> - - <listitem> - <para><emphasis>BUS_DMA_ISA</emphasis> - mysterious - flag used only on Alpha machines. It is not defined - for the i386 machines. Probably it should be used - by all the ISA drivers for Alpha machines but it - looks like there are no such drivers yet.</para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> - <para><emphasis>dmat</emphasis> - pointer to the storage - for the new tag to be returned</para> - </listitem> - - </itemizedlist> - - </listitem> - - <listitem> <!-- Second entry in list alpha --> - <para><function>int bus_dma_tag_destroy(bus_dma_tag_t - dmat)</function></para> - - <para>Destroy a tag. Returns 0 on success, the error code - otherwise.</para> - - <para>dmat - the tag to be destroyed</para> - - </listitem> - - <listitem> <!-- Third entry in list alpha --> - <para><function>int bus_dmamem_alloc(bus_dma_tag_t dmat, - void** vaddr, int flags, bus_dmamap_t - *mapp)</function></para> - - <para>Allocate an area of contiguous memory described by the - tag. The size of memory to be allocated is tag's maxsize. - Returns 0 on success, the error code otherwise. The result - still has to be loaded by - <function>bus_dmamap_load()</function> before used to get - the physical address of the memory.</para> - -<!-- XXX What it is Wylie, I got to here --> - - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>vaddr</emphasis> - pointer to the storage - for the kernel virtual address of the allocated area - to be returned. - </para> - </listitem> - <listitem> - <para> - flags - a bitmap of flags. The only interesting flag is: - </para> - <itemizedlist> - <listitem> - <para> - <emphasis>BUS_DMA_NOWAIT</emphasis> - if the - memory is not immediately available return the - error. If this flag is not set then the routine - is allowed to sleep waiting until the memory - will become available. - </para> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <para> - <emphasis>mapp</emphasis> - pointer to the storage - for the new map to be returned - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Fourth entry in list alpha --> - <para> - <function>void bus_dmamem_free(bus_dma_tag_t dmat, void - *vaddr, bus_dmamap_t map)</function> - </para> - <para> - Free the memory allocated by - <function>bus_dmamem_alloc()</function>. As of now - freeing of the memory allocated with ISA restrictions is - not implemented. Because of this the recommended model - of use is to keep and re-use the allocated areas for as - long as possible. Do not lightly free some area and then - shortly allocate it again. That does not mean that - <function>bus_dmamem_free()</function> should not be - used at all: hopefully it will be properly implemented - soon. - </para> - - <itemizedlist> - <listitem> - <para><emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>vaddr</emphasis> - the kernel virtual - address of the memory - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - the map of the memory (as - returned from - <function>bus_dmamem_alloc()</function>) - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- The fifth entry in list alpha --> - <para> - <function>int bus_dmamap_create(bus_dma_tag_t dmat, int - flags, bus_dmamap_t *mapp)</function> - </para> - <para> - Create a map for the tag, to be used in - <function>bus_dmamap_load()</function> later. Returns 0 - on success, the error code otherwise. - </para> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>flags</emphasis> - theoretically, a bit map - of flags. But no flags are defined yet, so as of now - it will be always 0. - </para> - </listitem> - <listitem> - <para> - <emphasis>mapp</emphasis> - pointer to the storage - for the new map to be returned - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Sixth entry in the alpha list --> - <para> - <function>int bus_dmamap_destroy(bus_dma_tag_t dmat, - bus_dmamap_t map)</function> - </para> - <para> - Destroy a map. Returns 0 on success, the error code otherwise. - </para> - - <itemizedlist> - <listitem> - <para> - dmat - the tag to which the map is associated - </para> - </listitem> - <listitem> - <para> - map - the map to be destroyed - </para> - </listitem> - </itemizedlist> - </listitem> - - <listitem> <!-- Seventh entry in list alpha --> - <para> - <function>int bus_dmamap_load(bus_dma_tag_t dmat, - bus_dmamap_t map, void *buf, bus_size_t buflen, - bus_dmamap_callback_t *callback, void *callback_arg, int - flags)</function> - </para> - <para> - Load a buffer into the map (the map must be previously - created by <function>bus_dmamap_create()</function> or - <function>bus_dmamem_alloc()</function>). All the pages - of the buffer are checked for conformance to the tag - requirements and for those not conformant the bounce - pages are allocated. An array of physical segment - descriptors is built and passed to the callback - routine. This callback routine is then expected to - handle it in some way. The number of bounce buffers in - the system is limited, so if the bounce buffers are - needed but not immediately available the request will be - queued and the callback will be called when the bounce - buffers will become available. Returns 0 if the callback - was executed immediately or EINPROGRESS if the request - was queued for future execution. In the latter case the - synchronization with queued callback routine is the - responsibility of the driver. - </para> - <!--<blockquote>--> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - the tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - the map - </para> - </listitem> - <listitem> - <para> - <emphasis>buf</emphasis> - kernel virtual address of - the buffer - </para> - </listitem> - <listitem> - <para> - <emphasis>buflen</emphasis> - length of the buffer - </para> - </listitem> - <listitem> - <para> - <emphasis>callback</emphasis>,<function> - callback_arg</function> - the callback function and - its argument - </para> - </listitem> - </itemizedlist> - <!--</blockquote>--> - <para> - The prototype of callback function is: - </para> - <para> - <function>void callback(void *arg, bus_dma_segment_t - *seg, int nseg, int error)</function> - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>arg</emphasis> - the same as callback_arg - passed to <function>bus_dmamap_load()</function> - </para> - </listitem> - <listitem> - <para> - <emphasis>seg</emphasis> - array of the segment - descriptors - </para> - </listitem> - <listitem> - <para> - <emphasis>nseg</emphasis> - number of descriptors in - array - </para> - </listitem> - <listitem> - <para> - <emphasis>error</emphasis> - indication of the - segment number overflow: if it's set to EFBIG then - the buffer did not fit into the maximal number of - segments permitted by the tag. In this case only the - permitted number of descriptors will be in the - array. Handling of this situation is up to the - driver: depending on the desired semantics it can - either consider this an error or split the buffer in - two and handle the second part separately - </para> - </listitem> - </itemizedlist> - <!-- </blockquote> --> - <para> - Each entry in the segments array contains the fields: - </para> - - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>ds_addr</emphasis> - physical bus address - of the segment - </para> - </listitem> - <listitem> - <para> - <emphasis>ds_len</emphasis> - length of the segment - </para> - </listitem> - </itemizedlist> - <!-- </blockquote>--> - </listitem> - - <listitem> <!-- Eighth entry in alpha list --> - <para> - <function>void bus_dmamap_unload(bus_dma_tag_t dmat, - bus_dmamap_t map)</function> - </para> - <para>unload the map. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - loaded map - </para> - </listitem> - </itemizedlist> - <!-- </blockquote> --> - </listitem> - - <listitem> <!-- Ninth entry list alpha --> - <para> - <function>void bus_dmamap_sync (bus_dma_tag_t dmat, - bus_dmamap_t map, bus_dmasync_op_t op)</function> - </para> - <para> - Synchronise a loaded buffer with its bounce pages before - and after physical transfer to or from device. This is - the function that does all the necessary copying of data - between the original buffer and its mapped version. The - buffers must be synchronized both before and after doing - the transfer. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>dmat</emphasis> - tag - </para> - </listitem> - <listitem> - <para> - <emphasis>map</emphasis> - loaded map - </para> - </listitem> - <listitem> - <para> - <emphasis>op</emphasis> - type of synchronization - operation to perform: - </para> - </listitem> - </itemizedlist> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <function>BUS_DMASYNC_PREREAD</function> - before - reading from device into buffer - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_POSTREAD</function> - after - reading from device into buffer - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_PREWRITE</function> - before - writing the buffer to device - </para> - </listitem> - <listitem> - <para> - <function>BUS_DMASYNC_POSTWRITE</function> - after - writing the buffer to device - </para> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> <!-- End of list alpha --> -<!-- </blockquote> -</blockquote> --> - - <para> - As of now PREREAD and POSTWRITE are null operations but that - may change in the future, so they must not be ignored in the - driver. Synchronization is not needed for the memory - obtained from <function>bus_dmamem_alloc()</function>. - </para> - <para> - Before calling the callback function from - <function>bus_dmamap_load()</function> the segment array is - stored in the stack. And it gets pre-allocated for the - maximal number of segments allowed by the tag. Because of - this the practical limit for the number of segments on i386 - architecture is about 250-300 (the kernel stack is 4KB minus - the size of the user structure, size of a segment array - entry is 8 bytes, and some space must be left). Because the - array is allocated based on the maximal number this value - must not be set higher than really needed. Fortunately, for - most of hardware the maximal supported number of segments is - much lower. But if the driver wants to handle buffers with a - very large number of scatter-gather segments it should do - that in portions: load part of the buffer, transfer it to - the device, load next part of the buffer, and so on. - </para> - <para> - Another practical consequence is that the number of segments - may limit the size of the buffer. If all the pages in the - buffer happen to be physically non-contiguous then the - maximal supported buffer size for that fragmented case would - be (nsegments * page_size). For example, if a maximal number - of 10 segments is supported then on i386 maximal guaranteed - supported buffer size would be 40K. If a higher size is - desired then special tricks should be used in the driver. - </para> - <para> - If the hardware does not support scatter-gather at all or - the driver wants to support some buffer size even if it's - heavily fragmented then the solution is to allocate a - contiguous buffer in the driver and use it as intermediate - storage if the original buffer does not fit. - </para> - <para> - Below are the typical call sequences when using a map depend - on the use of the map. The characters -> are used to show - the flow of time. - </para> - <para> - For a buffer which stays practically fixed during all the - time between attachment and detachment of a device:</para> - <para> - bus_dmamem_alloc -> bus_dmamap_load -> ...use buffer... -> - -> bus_dmamap_unload -> bus_dmamem_free - </para> - - <para>For a buffer that changes frequently and is passed from - outside the driver: - - <!-- XXX is this correct? --> - <programlisting> bus_dmamap_create -> - -> bus_dmamap_load -> bus_dmamap_sync(PRE...) -> do transfer -> - -> bus_dmamap_sync(POST...) -> bus_dmamap_unload -> - ... - -> bus_dmamap_load -> bus_dmamap_sync(PRE...) -> do transfer -> - -> bus_dmamap_sync(POST...) -> bus_dmamap_unload -> - -> bus_dmamap_destroy </programlisting> - - </para> - <para> - When loading a map created by - <function>bus_dmamem_alloc()</function> the passed address - and size of the buffer must be the same as used in - <function>bus_dmamem_alloc()</function>. In this case it is - guaranteed that the whole buffer will be mapped as one - segment (so the callback may be based on this assumption) - and the request will be executed immediately (EINPROGRESS - will never be returned). All the callback needs to do in - this case is to save the physical address. - </para> - <para> - A typical example would be: - </para> - - <programlisting> static void - alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error) - { - *(bus_addr_t *)arg = seg[0].ds_addr; - } - - ... - int error; - struct somedata { - .... - }; - struct somedata *vsomedata; /* virtual address */ - bus_addr_t psomedata; /* physical bus-relative address */ - bus_dma_tag_t tag_somedata; - bus_dmamap_t map_somedata; - ... - - error=bus_dma_tag_create(parent_tag, alignment, - boundary, lowaddr, highaddr, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ sizeof(struct somedata), /*nsegments*/ 1, - /*maxsegsz*/ sizeof(struct somedata), /*flags*/ 0, - &tag_somedata); - if(error) - return error; - - error = bus_dmamem_alloc(tag_somedata, &vsomedata, /* flags*/ 0, - &map_somedata); - if(error) - return error; - - bus_dmamap_load(tag_somedata, map_somedata, (void *)vsomedata, - sizeof (struct somedata), alloc_callback, - (void *) &psomedata, /*flags*/0); </programlisting> - - <para> - Looks a bit long and complicated but that's the way to do - it. The practical consequence is: if multiple memory areas - are allocated always together it would be a really good idea - to combine them all into one structure and allocate as one - (if the alignment and boundary limitations permit). - </para> - <para> - When loading an arbitrary buffer into the map created by - <function>bus_dmamap_create()</function> special measures - must be taken to synchronize with the callback in case it - would be delayed. The code would look like: - </para> - - <programlisting> { - int s; - int error; - - s = splsoftvm(); - error = bus_dmamap_load( - dmat, - dmamap, - buffer_ptr, - buffer_len, - callback, - /*callback_arg*/ buffer_descriptor, - /*flags*/0); - if (error == EINPROGRESS) { - /* - * Do whatever is needed to ensure synchronization - * with callback. Callback is guaranteed not to be started - * until we do splx() or tsleep(). - */ - } - splx(s); - } </programlisting> - - <para> - Two possible approaches for the processing of requests are: - </para> - <para> - 1. If requests are completed by marking them explicitly as - done (such as the CAM requests) then it would be simpler to - put all the further processing into the callback driver - which would mark the request when it's done. Then not much - extra synchronization is needed. For the flow control - reasons it may be a good idea to freeze the request queue - until this request gets completed. - </para> - <para> - 2. If requests are completed when the function returns (such - as classic read or write requests on character devices) then - a synchronization flag should be set in the buffer - descriptor and <function>tsleep()</function> called. Later - when the callback gets called it will do it's processing and - check this synchronization flag. If it's set then the - callback should issue a wakeup. In this approach the - callback function could either do all the needed processing - (just like the previous case) or simply save the segments - array in the buffer descriptor. Then after callback - completes the calling function could use this saved segments - array and do all the processing. - - </para> - </sect1> -<!--_________________________________________________________________________--> -<!--~~~~~~~~~~~~~~~~~~~~END OF SECTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> - - <sect1> - <title>DMA</title> - <!-- Section Marked up by Wylie --> - <para> - The Direct Memory Access (DMA) is implemented in the ISA bus - through the DMA controller (actually, two of them but that's - an irrelevant detail). To make the early ISA devices simple - and cheap the logic of the bus control and address - generation was concentrated in the DMA controller. - Fortunately, FreeBSD provides a set of functions that mostly - hide the annoying details of the DMA controller from the - device drivers. - </para> - - <para> - The simplest case is for the fairly intelligent - devices. Like the bus master devices on PCI they can - generate the bus cycles and memory addresses all by - themselves. The only thing they really need from the DMA - controller is bus arbitration. So for this purpose they - pretend to be cascaded slave DMA controllers. And the only - thing needed from the system DMA controller is to enable the - cascaded mode on a DMA channel by calling the following - function when attaching the driver: - </para> - - <para> - <function>void isa_dmacascade(int channel_number)</function> - </para> - - <para> - All the further activity is done by programming the - device. When detaching the driver no DMA-related functions - need to be called. - </para> - - <para> - For the simpler devices things get more complicated. The - functions used are: - </para> - - <itemizedlist> - - <listitem> - <para> - <function>int isa_dma_acquire(int chanel_number)</function> - </para> - <para> - Reserve a DMA channel. Returns 0 on success or EBUSY - if the channel was already reserved by this or a - different driver. Most of the ISA devices are not able - to share DMA channels anyway, so normally this - function is called when attaching a device. This - reservation was made redundant by the modern interface - of bus resources but still must be used in addition to - the latter. If not used then later, other DMA routines - will panic. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dma_release(int chanel_number)</function> - </para> - <para> - Release a previously reserved DMA channel. No - transfers must be in progress when the channel is - released (as well as the device must not try to - initiate transfer after the channel is released). - </para> - </listitem> - - <listitem> - <para> - <function>void isa_dmainit(int chan, u_int - bouncebufsize)</function> - </para> - <para> - Allocate a bounce buffer for use with the specified - channel. The requested size of the buffer can't exceed - 64KB. This bounce buffer will be automatically used - later if a transfer buffer happens to be not - physically contiguous or outside of the memory - accessible by the ISA bus or crossing the 64KB - boundary. If the transfers will be always done from - buffers which conform to these conditions (such as - those allocated by - <function>bus_dmamem_alloc()</function> with proper - limitations) then <function>isa_dmainit()</function> - does not have to be called. But it's quite convenient - to transfer arbitrary data using the DMA controller. - The bounce buffer will automatically care of the - scatter-gather issues. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - <emphasis>chan</emphasis> - channel number - </para> - </listitem> - <listitem> - <para> - <emphasis>bouncebufsize</emphasis> - size of the - bounce buffer in bytes - </para> - </listitem> - </itemizedlist> -<!-- </blockquote> --> -<!--</para> --> - </listitem> - - <listitem> - <para> - <function>void isa_dmastart(int flags, caddr_t addr, u_int - nbytes, int chan)</function> - </para> - <para> - Prepare to start a DMA transfer. This function must be - called to set up the DMA controller before actually - starting transfer on the device. It checks that the - buffer is contiguous and falls into the ISA memory - range, if not then the bounce buffer is automatically - used. If bounce buffer is required but not set up by - <function>isa_dmainit()</function> or too small for - the requested transfer size then the system will - panic. In case of a write request with bounce buffer - the data will be automatically copied to the bounce - buffer. - </para> - </listitem> - <listitem> - <para>flags - a bitmask determining the type of operation to - be done. The direction bits B_READ and B_WRITE are mutually - exclusive. - </para> - <!-- <blockquote> --> - <itemizedlist> - <listitem> - <para> - B_READ - read from the ISA bus into memory - </para> - </listitem> - <listitem> - <para> - B_WRITE - write from the memory to the ISA bus - </para> - </listitem> - <listitem> - <para> - B_RAW - if set then the DMA controller will remember - the buffer and after the end of transfer will - automatically re-initialize itself to repeat transfer - of the same buffer again (of course, the driver may - change the data in the buffer before initiating - another transfer in the device). If not set then the - parameters will work only for one transfer, and - <function>isa_dmastart()</function> will have to be - called again before initiating the next - transfer. Using B_RAW makes sense only if the bounce - buffer is not used. - </para> - </listitem> - </itemizedlist> -<!-- </blockquote> --> - </listitem> - <listitem> - <para> - addr - virtual address of the buffer - </para> - </listitem> - <listitem> - <para> - nbytes - length of the buffer. Must be less or equal to - 64KB. Length of 0 is not allowed: the DMA controller will - understand it as 64KB while the kernel code will - understand it as 0 and that would cause unpredictable - effects. For channels number 4 and higher the length must - be even because these channels transfer 2 bytes at a - time. In case of an odd length the last byte will not be - transferred. - </para> - </listitem> - <listitem> - <para> - chan - channel number - </para> - </listitem> - - <listitem> - <para> - <function>void isa_dmadone(int flags, caddr_t addr, int - nbytes, int chan)</function> - </para> - <para> - Synchronize the memory after device reports that transfer - is done. If that was a read operation with a bounce buffer - then the data will be copied from the bounce buffer to the - original buffer. Arguments are the same as for - <function>isa_dmastart()</function>. Flag B_RAW is - permitted but it does not affect - <function>isa_dmadone()</function> in any way. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dmastatus(int channel_number)</function> - </para> - <para> - Returns the number of bytes left in the current transfer - to be transferred. In case the flag B_READ was set in - <function>isa_dmastart()</function> the number returned - will never be equal to zero. At the end of transfer it - will be automatically reset back to the length of - buffer. The normal use is to check the number of bytes - left after the device signals that the transfer is - completed. If the number of bytes is not 0 then probably - something went wrong with that transfer. - </para> - </listitem> - - <listitem> - <para> - <function>int isa_dmastop(int channel_number)</function> - </para> - <para> - Aborts the current transfer and returns the number of - bytes left untransferred. - </para> - </listitem> - </itemizedlist> - </sect1> - - <sect1> - <title>xxx_isa_probe</title> - <!-- Section marked up by Wylie --> - - <para> - This function probes if a device is present. If the driver - supports auto-detection of some part of device configuration - (such as interrupt vector or memory address) this - auto-detection must be done in this routine. - </para> - - <para> - As for any other bus, if the device cannot be detected or - is detected but failed the self-test or some other problem - happened then it returns a positive value of error. The - value ENXIO must be returned if the device is not - present. Other error values may mean other conditions. Zero - or negative values mean success. Most of the drivers return - zero as success. - </para> - - <para> - The negative return values are used when a PnP device - supports multiple interfaces. For example, an older - compatibility interface and a newer advanced interface which - are supported by different drivers. Then both drivers would - detect the device. The driver which returns a higher value - in the probe routine takes precedence (in other words, the - driver returning 0 has highest precedence, one returning -1 - is next, one returning -2 is after it and so on). In result - the devices which support only the old interface will be - handled by the old driver (which should return -1 from the - probe routine) while the devices supporting the new - interface as well will be handled by the new driver (which - should return 0 from the probe routine). - </para> - - <para> - The device descriptor struct xxx_softc is allocated by the - system before calling the probe routine. If the probe - routine returns an error the descriptor will be - automatically deallocated by the system. So if a probing - error occurs the driver must make sure that all the - resources it used during probe are deallocated and that - nothing keeps the descriptor from being safely - deallocated. If the probe completes successfully the - descriptor will be preserved by the system and later passed - to the routine <function>xxx_isa_attach()</function>. If a - driver returns a negative value it can't be sure that it - will have the highest priority and its attach routine will - be called. So in this case it also must release all the - resources before returning and if necessary allocate them - again in the attach routine. When - <function>xxx_isa_probe()</function> returns 0 releasing the - resources before returning is also a good idea, a - well-behaved driver should do so. But in case if there is - some problem with releasing the resources the driver is - allowed to keep resources between returning 0 from the probe - routine and execution of the attach routine. - </para> - - <para> - A typical probe routine starts with getting the device - descriptor and unit: - </para> - - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int unit = device_get_unit(dev); - int pnperror; - int error = 0; - - sc->dev = dev; /* link it back */ - sc->unit = unit; </programlisting> - - <para> - Then check for the PnP devices. The check is carried out by - a table containing the list of PnP IDs supported by this - driver and human-readable descriptions of the device models - corresponding to these IDs. - </para> - - <programlisting> - pnperror=ISA_PNP_PROBE(device_get_parent(dev), dev, - xxx_pnp_ids); if(pnperror == ENXIO) return ENXIO; - </programlisting> - - <para> - The logic of ISA_PNP_PROBE is the following: If this card - (device unit) was not detected as PnP then ENOENT will be - returned. If it was detected as PnP but its detected ID does - not match any of the IDs in the table then ENXIO is - returned. Finally, if it has PnP support and it matches on - of the IDs in the table, 0 is returned and the appropriate - description from the table is set by - <function>device_set_desc()</function>. - </para> - - <para> - If a driver supports only PnP devices then the condition - would look like: - </para> - - <programlisting> if(pnperror != 0) - return pnperror; </programlisting> - - <para> - No special treatment is required for the drivers which don't - support PnP because they pass an empty PnP ID table and will - always get ENXIO if called on a PnP card. - </para> - - <para> - The probe routine normally needs at least some minimal set - of resources, such as I/O port number to find the card and - probe it. Depending on the hardware the driver may be able - to discover the other necessary resources automatically. The - PnP devices have all the resources pre-set by the PnP - subsystem, so the driver does not need to discover them by - itself. - </para> - - <para> - Typically the minimal information required to get access to - the device is the I/O port number. Then some devices allow - to get the rest of information from the device configuration - registers (though not all devices do that). So first we try - to get the port start value: - </para> - - <programlisting> sc->port0 = bus_get_resource_start(dev, - SYS_RES_IOPORT, 0 /*rid*/); if(sc->port0 == 0) return ENXIO; - </programlisting> - - <para> - The base port address is saved in the structure softc for - future use. If it will be used very often then calling the - resource function each time would be prohibitively slow. If - we don't get a port we just return an error. Some device - drivers can instead be clever and try to probe all the - possible ports, like this: - </para> - - <programlisting> - /* table of all possible base I/O port addresses for this device */ - static struct xxx_allports { - u_short port; /* port address */ - short used; /* flag: if this port is already used by some unit */ - } xxx_allports = { - { 0x300, 0 }, - { 0x320, 0 }, - { 0x340, 0 }, - { 0, 0 } /* end of table */ - }; - - ... - int port, i; - ... - - port = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/); - if(port !=0 ) { - for(i=0; xxx_allports[i].port!=0; i++) { - if(xxx_allports[i].used || xxx_allports[i].port != port) - continue; - - /* found it */ - xxx_allports[i].used = 1; - /* do probe on a known port */ - return xxx_really_probe(dev, port); - } - return ENXIO; /* port is unknown or already used */ - } - - /* we get here only if we need to guess the port */ - for(i=0; xxx_allports[i].port!=0; i++) { - if(xxx_allports[i].used) - continue; - - /* mark as used - even if we find nothing at this port - * at least we won't probe it in future - */ - xxx_allports[i].used = 1; - - error = xxx_really_probe(dev, xxx_allports[i].port); - if(error == 0) /* found a device at that port */ - return 0; - } - /* probed all possible addresses, none worked */ - return ENXIO;</programlisting> - - <para> - Of course, normally the driver's - <function>identify()</function> routine should be used for - such things. But there may be one valid reason why it may be - better to be done in <function>probe()</function>: if this - probe would drive some other sensitive device crazy. The - probe routines are ordered with consideration of the - "sensitive" flag: the sensitive devices get probed first and - the rest of devices later. But the - <function>identify()</function> routines are called before - any probes, so they show no respect to the sensitive devices - and may upset them. - </para> - - <para> - Now, after we got the starting port we need to set the port - count (except for PnP devices) because the kernel does not - have this information in the configuration file. - </para> - - <programlisting> - if(pnperror /* only for non-PnP devices */ - && bus_set_resource(dev, SYS_RES_IOPORT, 0, sc->port0, - XXX_PORT_COUNT)<0) - return ENXIO;</programlisting> - - <para> - Finally allocate and activate a piece of port address space - (special values of start and end mean "use those we set by - <function>bus_set_resource()</function>"): - </para> - - <programlisting> - sc->port0_rid = 0; - sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, - &sc->port0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->port0_r == NULL) - return ENXIO;</programlisting> - - <para> - Now having access to the port-mapped registers we can poke - the device in some way and check if it reacts like it is - expected to. If it does not then there is probably some - other device or no device at all at this address. - </para> - - <para> - Normally drivers don't set up the interrupt handlers until - the attach routine. Instead they do probes in the polling - mode using the <function>DELAY()</function> function for - timeout. The probe routine must never hang forever, all the - waits for the device must be done with timeouts. If the - device does not respond within the time it's probably broken - or misconfigured and the driver must return error. When - determining the timeout interval give the device some extra - time to be on the safe side: although - <function>DELAY()</function> is supposed to delay for the - same amount of time on any machine it has some margin of - error, depending on the exact CPU. - </para> - - <para> - If the probe routine really wants to check that the - interrupts really work it may configure and probe the - interrupts too. But that's not recommended. - </para> - - <programlisting> - /* implemented in some very device-specific way */ - if(error = xxx_probe_ports(sc)) - goto bad; /* will deallocate the resources before returning */ - </programlisting> - - <para> - The fucntion <function>xxx_probe_ports()</function> may also - set the device description depending on the exact model of - device it discovers. But if there is only one supported - device model this can be as well done in a hardcoded way. - Of course, for the PnP devices the PnP support sets the - description from the table automatically. - </para> - - - <programlisting> if(pnperror) - device_set_desc(dev, "Our device model 1234"); - </programlisting> - - <para> - Then the probe routine should either discover the ranges of - all the resources by reading the device configuration - registers or make sure that they were set explicitly by the - user. We will consider it with an example of on-board - memory. The probe routine should be as non-intrusive as - possible, so allocation and check of functionality of the - rest of resources (besides the ports) would be better left - to the attach routine. - </para> - - <para> - The memory address may be specified in the kernel - configuration file or on some devices it may be - pre-configured in non-volatile configuration registers. If - both sources are available and different, which one should - be used? Probably if the user bothered to set the address - explicitly in the kernel configuration file they know what - they're doing and this one should take precedence. An - example of implementation could be: - </para> - <programlisting> - /* try to find out the config address first */ - sc->mem0_p = bus_get_resource_start(dev, SYS_RES_MEMORY, 0 /*rid*/); - if(sc->mem0_p == 0) { /* nope, not specified by user */ - sc->mem0_p = xxx_read_mem0_from_device_config(sc); - - - if(sc->mem0_p == 0) - /* can't get it from device config registers either */ - goto bad; - } else { - if(xxx_set_mem0_address_on_device(sc) < 0) - goto bad; /* device does not support that address */ - } - - /* just like the port, set the memory size, - * for some devices the memory size would not be constant - * but should be read from the device configuration registers instead - * to accommodate different models of devices. Another option would - * be to let the user set the memory size as "msize" configuration - * resource which will be automatically handled by the ISA bus. - */ - if(pnperror) { /* only for non-PnP devices */ - sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/); - if(sc->mem0_size == 0) /* not specified by user */ - sc->mem0_size = xxx_read_mem0_size_from_device_config(sc); - - if(sc->mem0_size == 0) { - /* suppose this is a very old model of device without - * auto-configuration features and the user gave no preference, - * so assume the minimalistic case - * (of course, the real value will vary with the driver) - */ - sc->mem0_size = 8*1024; - } - - if(xxx_set_mem0_size_on_device(sc) < 0) - goto bad; /* device does not support that size */ - - if(bus_set_resource(dev, SYS_RES_MEMORY, /*rid*/0, - sc->mem0_p, sc->mem0_size)<0) - goto bad; - } else { - sc->mem0_size = bus_get_resource_count(dev, SYS_RES_MEMORY, 0 /*rid*/); - } </programlisting> - - <para> - Resources for IRQ and DRQ are easy to check by analogy. - </para> - - <para> - If all went well then release all the resources and return success. - </para> - - <programlisting> xxx_free_resources(sc); - return 0;</programlisting> - - <para> - Finally, handle the troublesome situations. All the - resources should be deallocated before returning. We make - use of the fact that before the structure softc is passed to - us it gets zeroed out, so we can find out if some resource - was allocated: then its descriptor is non-zero. - </para> - - <programlisting> bad: - - xxx_free_resources(sc); - if(error) - return error; - else /* exact error is unknown */ - return ENXIO;</programlisting> - - <para> - That would be all for the probe routine. Freeing of - resources is done from multiple places, so it's moved to a - function which may look like: - </para> - -<programlisting>static void - xxx_free_resources(sc) - struct xxx_softc *sc; - { - /* check every resource and free if not zero */ - - /* interrupt handler */ - if(sc->intr_r) { - bus_teardown_intr(sc->dev, sc->intr_r, sc->intr_cookie); - bus_release_resource(sc->dev, SYS_RES_IRQ, sc->intr_rid, - sc->intr_r); - sc->intr_r = 0; - } - - /* all kinds of memory maps we could have allocated */ - if(sc->data_p) { - bus_dmamap_unload(sc->data_tag, sc->data_map); - sc->data_p = 0; - } - if(sc->data) { /* sc->data_map may be legitimately equal to 0 */ - /* the map will also be freed */ - bus_dmamem_free(sc->data_tag, sc->data, sc->data_map); - sc->data = 0; - } - if(sc->data_tag) { - bus_dma_tag_destroy(sc->data_tag); - sc->data_tag = 0; - } - - ... free other maps and tags if we have them ... - - if(sc->parent_tag) { - bus_dma_tag_destroy(sc->parent_tag); - sc->parent_tag = 0; - } - - /* release all the bus resources */ - if(sc->mem0_r) { - bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->mem0_rid, - sc->mem0_r); - sc->mem0_r = 0; - } - ... - if(sc->port0_r) { - bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->port0_rid, - sc->port0_r); - sc->port0_r = 0; - } - }</programlisting> - - </sect1> - - <sect1> - <title>xxx_isa_attach</title> - <!-- Section Marked up by Wylie --> - - <para>The attach routine actually connects the driver to the - system if the probe routine returned success and the system - had chosen to attach that driver. If the probe routine - returned 0 then the attach routine may expect to receive the - device structure softc intact, as it was set by the probe - routine. Also if the probe routine returns 0 it may expect - that the attach routine for this device shall be called at - some point in the future. If the probe routine returns a - negative value then the driver may make none of these - assumptions. - </para> - - <para>The attach routine returns 0 if it completed successfully or - error code otherwise. - </para> - - <para>The attach routine starts just like the probe routine, - with getting some frequently used data into more accessible - variables. - </para> - - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int unit = device_get_unit(dev); - int error = 0;</programlisting> - - <para>Then allocate and activate all the necessary - resources. Because normally the port range will be released - before returning from probe, it has to be allocated - again. We expect that the probe routine had properly set all - the resource ranges, as well as saved them in the structure - softc. If the probe routine had left some resource allocated - then it does not need to be allocated again (which would be - considered an error). - </para> - - <programlisting> sc->port0_rid = 0; - sc->port0_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->port0_r == NULL) - return ENXIO; - - /* on-board memory */ - sc->mem0_rid = 0; - sc->mem0_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem0_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->mem0_r == NULL) - goto bad; - - /* get its virtual address */ - sc->mem0_v = rman_get_virtual(sc->mem0_r);</programlisting> - - <para>The DMA request channel (DRQ) is allocated likewise. To - initialize it use functions of the - <function>isa_dma*()</function> family. For example: - </para> - - <para><function>isa_dmacascade(sc->drq0);</function></para> - - <para>The interrupt request line (IRQ) is a bit - special. Besides allocation the driver's interrupt handler - should be associated with it. Historically in the old ISA - drivers the argument passed by the system to the interrupt - handler was the device unit number. But in modern drivers - the convention suggests passing the pointer to structure - softc. The important reason is that when the structures - softc are allocated dynamically then getting the unit number - from softc is easy while getting softc from unit number is - difficult. Also this convention makes the drivers for - different buses look more uniform and allows them to share - the code: each bus gets its own probe, attach, detach and - other bus-specific routines while the bulk of the driver - code may be shared among them. - </para> - - <programlisting> - sc->intr_rid = 0; - sc->intr_r = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->intr_rid, - /*start*/ 0, /*end*/ ~0, /*count*/ 0, RF_ACTIVE); - - if(sc->intr_r == NULL) - goto bad; - - /* - * XXX_INTR_TYPE is supposed to be defined depending on the type of - * the driver, for example as INTR_TYPE_CAM for a CAM driver - */ - error = bus_setup_intr(dev, sc->intr_r, XXX_INTR_TYPE, - (driver_intr_t *) xxx_intr, (void *) sc, &sc->intr_cookie); - if(error) - goto bad; - - </programlisting> - - - <para>If the device needs to make DMA to the main memory then - this memory should be allocated like described before: - </para> - - <programlisting> error=bus_dma_tag_create(NULL, /*alignment*/ 4, - /*boundary*/ 0, /*lowaddr*/ BUS_SPACE_MAXADDR_24BIT, - /*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ BUS_SPACE_MAXSIZE_24BIT, - /*nsegments*/ BUS_SPACE_UNRESTRICTED, - /*maxsegsz*/ BUS_SPACE_MAXSIZE_24BIT, /*flags*/ 0, - &sc->parent_tag); - if(error) - goto bad; - - /* many things get inherited from the parent tag - * sc->data is supposed to point to the structure with the shared data, - * for example for a ring buffer it could be: - * struct { - * u_short rd_pos; - * u_short wr_pos; - * char bf[XXX_RING_BUFFER_SIZE] - * } *data; - */ - error=bus_dma_tag_create(sc->parent_tag, 1, - 0, BUS_SPACE_MAXADDR, 0, /*filter*/ NULL, /*filterarg*/ NULL, - /*maxsize*/ sizeof(* sc->data), /*nsegments*/ 1, - /*maxsegsz*/ sizeof(* sc->data), /*flags*/ 0, - &sc->data_tag); - if(error) - goto bad; - - error = bus_dmamem_alloc(sc->data_tag, &sc->data, /* flags*/ 0, - &sc->data_map); - if(error) - goto bad; - - /* xxx_alloc_callback() just saves the physical address at - * the pointer passed as its argument, in this case &sc->data_p. - * See details in the section on bus memory mapping. - * It can be implemented like: - * - * static void - * xxx_alloc_callback(void *arg, bus_dma_segment_t *seg, - * int nseg, int error) - * { - * *(bus_addr_t *)arg = seg[0].ds_addr; - * } - */ - bus_dmamap_load(sc->data_tag, sc->data_map, (void *)sc->data, - sizeof (* sc->data), xxx_alloc_callback, (void *) &sc->data_p, - /*flags*/0);</programlisting> - - - <para>After all the necessary resources are allocated the - device should be initialized. The initialization may include - testing that all the expected features are functional.</para> - - <programlisting> if(xxx_initialize(sc) < 0) - goto bad; </programlisting> - - - <para>The bus subsystem will automatically print on the - console the device description set by probe. But if the - driver wants to print some extra information about the - device it may do so, for example:</para> - - <programlisting> - device_printf(dev, "has on-card FIFO buffer of %d bytes\n", sc->fifosize); - </programlisting> - - <para>If the initialization routine experiences any problems - then printing messages about them before returning error is - also recommended.</para> - - <para>The final step of the attach routine is attaching the - device to its functional subsystem in the kernel. The exact - way to do it depends on the type of the driver: a character - device, a block device, a network device, a CAM SCSI bus - device and so on.</para> - - <para>If all went well then return success.</para> - - <programlisting> error = xxx_attach_subsystem(sc); - if(error) - goto bad; - - return 0; </programlisting> - - <para>Finally, handle the troublesome situations. All the - resources should be deallocated before returning an - error. We make use of the fact that before the structure - softc is passed to us it gets zeroed out, so we can find out - if some resource was allocated: then its descriptor is - non-zero.</para> - - <programlisting> bad: - - xxx_free_resources(sc); - if(error) - return error; - else /* exact error is unknown */ - return ENXIO;</programlisting> - - <para>That would be all for the attach routine.</para> - - </sect1> - - - <sect1> - <title>xxx_isa_detach</title> - - <para> - If this function is present in the driver and the driver is - compiled as a loadable module then the driver gets the - ability to be unloaded. This is an important feature if the - hardware supports hot plug. But the ISA bus does not support - hot plug, so this feature is not particularly important for - the ISA devices. The ability to unload a driver may be - useful when debugging it, but in many cases installation of - the new version of the driver would be required only after - the old version somehow wedges the system and reboot will be - needed anyway, so the efforts spent on writing the detach - routine may not be worth it. Another argument is that - unloading would allow upgrading the drivers on a production - machine seems to be mostly theoretical. Installing a new - version of a driver is a dangerous operation which should - never be performed on a production machine (and which is not - permitted when the system is running in secure mode). Still - the detach routine may be provided for the sake of - completeness. - </para> - - <para> - The detach routine returns 0 if the driver was successfully - detached or the error code otherwise. - </para> - - <para> - The logic of detach is a mirror of the attach. The first - thing to do is to detach the driver from its kernel - subsystem. If the device is currently open then the driver - has two choices: refuse to be detached or forcibly close and - proceed with detach. The choice used depends on the ability - of the particular kernel subsystem to do a forced close and - on the preferences of the driver's author. Generally the - forced close seems to be the preferred alternative. - <programlisting> struct xxx_softc *sc = device_get_softc(dev); - int error; - - error = xxx_detach_subsystem(sc); - if(error) - return error;</programlisting> - </para> - <para> - Next the driver may want to reset the hardware to some - consistent state. That includes stopping any ongoing - transfers, disabling the DMA channels and interrupts to - avoid memory corruption by the device. For most of the - drivers this is exactly what the shutdown routine does, so - if it is included in the driver we can as well just call it. - </para> - <para><function>xxx_isa_shutdown(dev);</function></para> - - <para> - And finally release all the resources and return success. - <programlisting> xxx_free_resources(sc); - return 0;</programlisting> - - </para> - </sect1> - - <sect1> - <title>xxx_isa_shutdown</title> - - <para> - This routine is called when the system is about to be shut - down. It is expected to bring the hardware to some - consistent state. For most of the ISA devices no special - action is required, so the function is not really necessary - because the device will be re-initialized on reboot - anyway. But some devices have to be shut down with a special - procedure, to make sure that they will be properly detected - after soft reboot (this is especially true for many devices - with proprietary identification protocols). In any case - disabling DMA and interrupts in the device registers and - stopping any ongoing transfers is a good idea. The exact - action depends on the hardware, so we don't consider it here - in any details. - </para> - - <para> - xxx_intr - </para> - - <para> - The interrupt handler is called when an interrupt is - received which may be from this particular device. The ISA - bus does not support interrupt sharing (except some special - cases) so in practice if the interrupt handler is called - then the interrupt almost for sure came from its - device. Still the interrupt handler must poll the device - registers and make sure that the interrupt was generated by - its device. If not it should just return. - </para> - - <para> - The old convention for the ISA drivers was getting the - device unit number as an argument. It is obsolete, and the - new drivers receive whatever argument was specified for them - in the attach routine when calling - <function>bus_setup_intr()</function>. By the new convention - it should be the pointer to the structure softc. So the - interrupt handler commonly starts as: - </para> - - <programlisting> - static void - xxx_intr(struct xxx_softc *sc) - { - - </programlisting> - - <para> - It runs at the interrupt priority level specified by the - interrupt type parameter of - <function>bus_setup_intr()</function>. That means that all - the other interrupts of the same type as well as all the - software interrupts are disabled. - </para> - - <para> - To avoid races it is commonly written as a loop: - </para> - - <programlisting> - while(xxx_interrupt_pending(sc)) { - xxx_process_interrupt(sc); - xxx_acknowledge_interrupt(sc); - } </programlisting> - - <para> - The interrupt handler has to acknowledge interrupt to the - device only but not to the interrupt controller, the system - takes care of the latter. - </para> - - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.sgml deleted file mode 100644 index a9ea688b9a..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/kobj/chapter.sgml +++ /dev/null @@ -1,298 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> - -<chapter id="kernel-objects"> - <title>Kernel Objects</title> - - <para>Kernel Objects, or <firstterm>Kobj</firstterm> provides an - object-oriented C programming system for the kernel. As such the - data being operated on carries the description of how to operate - on it. This allows operations to be added and removed from an - interface at run time and without breaking binary - compatibility.</para> - - <sect1> - <title>Terminology</title> - - <variablelist> - <varlistentry> - <term>Object</term> - <listitem><para>A set of data - data structure - data - allocation.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Method</term> - <listitem> - <para>An operation - function.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Class</term> - <listitem> - <para>One or more methods.</para> - </listitem> - </varlistentry> - <varlistentry> - <term>Interface</term> - <listitem> - <para>A standard set of one or more methods.</para> - </listitem> - </varlistentry> - </variablelist> - </sect1> - - <sect1> - <title>Kobj Operation</title> - - <para>Kobj works by generating descriptions of methods. Each - description holds a unique id as well as a default function. The - description's address is used to uniquely identify the method - within a class' method table.</para> - - <para>A class is built by creating a method table associating one - or more functions with method descriptions. Before use the class - is compiled. The compilation allocates a cache and associates it - with the class. A unique id is assigned to each method - description within the method table of the class if not already - done so by another referencing class compilation. For every - method to be used a function is generated by script to qualify - arguments and automatically reference the method description for - a lookup. The generated function looks up the method by using - the unique id associated with the method description as a hash - into the cache associated with the object's class. If the method - is not cached the generated function proceeds to use the class' - table to find the method. If the method is found then the - associated function within the class is used; otherwise, the - default function associated with the method description is - used.</para> - - <para>These indirections can be visualized as the - following:</para> - - <programlisting>object->cache<->class</programlisting> - - </sect1> - - <sect1> - <title>Using Kobj</title> - - <sect2> - <title>Structures</title> - - <programlisting>struct kobj_method</programlisting> - </sect2> - - <sect2> - <title>Functions</title> - - <programlisting>void kobj_class_compile(kobj_class_t cls); -void kobj_class_compile_static(kobj_class_t cls, kobj_ops_t ops); -void kobj_class_free(kobj_class_t cls); -kobj_t kobj_create(kobj_class_t cls, struct malloc_type *mtype, int mflags); -void kobj_init(kobj_t obj, kobj_class_t cls); -void kobj_delete(kobj_t obj, struct malloc_type *mtype);</programlisting> - </sect2> - - <sect2> - <title>Macros</title> - - <programlisting>KOBJ_CLASS_FIELDS -KOBJ_FIELDS -DEFINE_CLASS(name, methods, size) -KOBJMETHOD(NAME, FUNC)</programlisting> - </sect2> - - <sect2> - <title>Headers</title> - - <programlisting><sys/param.h> -<sys/kobj.h></programlisting> - </sect2> - - <sect2> - <title>Creating an interface template</title> - - <para>The first step in using Kobj is to create an - Interface. Creating the interface involves creating a template - that the script - <filename>src/sys/kern/makeobjops.pl</filename> can use to - generate the header and code for the method declarations and - method lookup functions.</para> - - <para>Within this template the following keywords are used: - <literal>#include</literal>, <literal>INTERFACE</literal>, - <literal>CODE</literal>, <literal>METHOD</literal>, - <literal>STATICMETHOD</literal>, and - <literal>DEFAULT</literal>.</para> - - <para>The <literal>#include</literal> statement and what follows - it is copied verbatim to the head of the generated code - file.</para> - - <para>For example:</para> - - <programlisting>#include <sys/foo.h></programlisting> - - <para>The <literal>INTERFACE</literal> keyword is used to define - the interface name. This name is concatenated with each method - name as [interface name]_[method name]. It's syntax is - INTERFACE [interface name];.</para> - - <para>For example:</para> - - <programlisting>INTERFACE foo;</programlisting> - - <para>The <literal>CODE</literal> keyword copies its arguments - verbatim into the code file. It's syntax is - <literal>CODE { [whatever] };</literal></para> - - <para>For example:</para> - - <programlisting>CODE { - struct foo * foo_alloc_null(struct bar *) - { - return NULL; -} -};</programlisting> - - <para>The <literal>METHOD</literal> keyword describes a method. It's syntax is - <literal>METHOD [return type] [method name] { [object [, - arguments]] };</literal></para> - - <para>For example:</para> - - <programlisting>METHOD int bar { - struct object *; - struct foo *; - struct bar; -};</programlisting> - - <para>The <literal>DEFAULT</literal> keyword may follow the - <literal>METHOD</literal> keyword. It extends the - <literal>METHOD</literal> key word to include the default - function for method. The extended syntax is - <literal>METHOD [return type] [method name] { - [object; [other arguments]] }DEFAULT [default - function];</literal></para> - - <para>For example:</para> - - <programlisting>METHOD int bar { - struct object *; - struct foo *; - int bar; -} DEFAULT foo_hack;</programlisting> - - <para>The <literal>STATICMETHOD</literal> keyword is used like - the <literal>METHOD</literal> keyword except the kobj data isn't - at the head of the object structure so casting to kobj_t would - be incorrect. Instead <literal>STATICMETHOD</literal> relies on the Kobj data being - referenced as 'ops'. This is also useful for calling - methods directly out of a class's method table.</para> - - <para>Other complete examples:</para> - - <programlisting>src/sys/kern/bus_if.m -src/sys/kern/device_if.m</programlisting> - - </sect2> - - <sect2> - <title>Creating a Class</title> - - <para>The second step in using Kobj is to create a class. A - class consists of a name, a table of methods, and the size of - objects if Kobj's object handling facilities are used. To - create the class use the macro - <function>DEFINE_CLASS()</function>. To create the method - table create an array of kobj_method_t terminated by a NULL - entry. Each non-NULL entry may be created using the macro - <function>KOBJMETHOD()</function>.</para> - - <para>For example:</para> - - <programlisting>DEFINE_CLASS(fooclass, foomethods, sizeof(struct foodata)); - -kobj_method_t foomethods[] = { - KOBJMETHOD(bar_doo, foo_doo), - KOBJMETHOD(bar_foo, foo_foo), - { NULL, NULL} -};</programlisting> - - <para>The class must be <quote>compiled</quote>. Depending on - the state of the system at the time that the class is to be - initialized a statically allocated cache, <quote>ops - table</quote> have to be used. This can be accomplished by - declaring a <structname>struct kobj_ops</structname> and using - <function>kobj_class_compile_static();</function> otherwise, - <function>kobj_class_compile()</function> should be used.</para> - </sect2> - - <sect2> - <title>Creating an Object</title> - - <para>The third step in using Kobj involves how to define the - object. Kobj object creation routines assume that Kobj data is - at the head of an object. If this in not appropriate you will - have to allocate the object yourself and then use - <function>kobj_init()</function> on the Kobj portion of it; - otherwise, you may use <function>kobj_create()</function> to - allocate and initialize the Kobj portion of the object - automatically. <function>kobj_init()</function> may also be - used to change the class that an object uses.</para> - - <para>To integrate Kobj into the object you should use the macro - KOBJ_FIELDS.</para> - - <para>For example</para> - - <programlisting>struct foo_data { - KOBJ_FIELDS; - foo_foo; - foo_bar; -};</programlisting> - </sect2> - - <sect2> - <title>Calling Methods</title> - - <para>The last step in using Kobj is to simply use the generated - functions to use the desired method within the object's - class. This is as simple as using the interface name and the - method name with a few modifications. The interface name - should be concatenated with the method name using a '_' - between them, all in upper case.</para> - - <para>For example, if the interface name was foo and the method - was bar then the call would be:</para> - - <programlisting>[return value = ] FOO_BAR(object [, other parameters]);</programlisting> - - </sect2> - - <sect2> - <title>Cleaning Up</title> - - <para>When an object allocated through - <function>kobj_create()</function> is no longer needed - <function>kobj_delete()</function> may be called on it, and - when a class is no longer being used - <function>kobj_class_free()</function> may be called on it.</para> - </sect2> - </sect1> -</chapter> - -<!-- - Local Variables: - mode: sgml - sgml-declaration: "../chapter.decl" - sgml-indent-data: t - sgml-omittag: nil - sgml-always-quote-attributes: t - sgml-parent-document: ("../book.sgml" "part" "chapter") - End: ---> diff --git a/en_US.ISO8859-1/books/arch-handbook/locking/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/locking/chapter.sgml deleted file mode 100644 index 993d649ffc..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/locking/chapter.sgml +++ /dev/null @@ -1,333 +0,0 @@ -<!-- - The FreeBSD Documentation Project - The FreeBSD SMP Next Generation Project - - $FreeBSD: doc/en_US.ISO_8859-1/books/developers-handbook/locking/chapter.sgml,v 1.1 2000/11/29 04:15:17 jhb Exp $ ---> - -<chapter id="locking"> - <title>Locking Notes</title> - - <para><emphasis>This chapter is maintained by the FreeBSD SMP Next - Generation Project - <email>freebsd-smp@FreeBSD.org</email>.</emphasis></para> - - - <para>This document outlines the locking used in the FreeBSD kernel - to permit effective multi-processing within the kernel. Locking - can be achieved via several means. Data structures can be - protected by mutexes or &man.lockmgr.9; locks. A few variables - are protected simply by always using atomic operations to access - them.</para> - - <sect1> - <title>Mutexes</title> - - <para>A mutex is simply a lock used to guarantee mutual exclusion. - Specifically, a mutex may only be owned by one entity at a time. - If another entity wishes to obtain a mutex that is already - owned, it must wait until the mutex is released. In the FreeBSD - kernel, mutexes are owned by processes.</para> - - <para>Mutexes may be recursively acquired, but they are intended - to be held for a short period of time. Specifically, one may - not sleep while holding a mutex. If you need to hold a lock - across a sleep, use a &man.lockmgr.9; lock.</para> - - <para>Each mutex has several properties of interest:</para> - - <variablelist> - <varlistentry> - <term>Variable Name</term> - <listitem> - <para>The name of the <type>struct mtx</type> variable in - the kernel source.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Logical Name</term> - <listitem> - <para>The name of the mutex assigned to it by - <function>mtx_init</function>. This name is displayed in - KTR trace messages and witness errors and warnings and is - used to distinguish mutexes in the witness code.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Type</term> - <listitem> - <para>The type of the mutex in terms of the - <constant>MTX_*</constant> flags. The meaning for each - flag is related to its meaning as documented in - &man.mutex.9;.</para> - - <variablelist> - <varlistentry> - <term><constant>MTX_DEF</constant></term> - <listitem> - <para>A sleep mutex</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_SPIN</constant></term> - <listitem> - <para>A spin mutex</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_COLD</constant></term> - <listitem> - <para>This mutex is initialized very early. Thus, it - must be declared via - <function>MUTEX_DECLARE</function>, and the - <constant>MTX_COLD</constant> flag must be passed to - <function>mtx_init</function>.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_TOPHALF</constant></term> - <listitem> - <para>This spin mutex does not disable - interrupts.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><constant>MTX_NORECURSE</constant></term> - <listitem> - <para>This mutex is not allowed to recurse.</para> - </listitem> - </varlistentry> - </variablelist> - </listitem> - </varlistentry> - - <varlistentry> - <term>Protectees</term> - <listitem> - <para>A list of data structures or data structure members - that this entry protects. For data structure members, the - name will be in the form of - <structname/structure name/.<structfield/member name/.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Dependent Functions</term> - <listitem> - <para>Functions that can only be called if this mutex is - held.</para> - </listitem> - </varlistentry> - </variablelist> - - <table frame="all" colsep="1" rowsep="1" pgwide="1"> - <title>Mutex List</title> - - <tgroup cols="5"> - <thead> - <row> - <entry>Variable Name</entry> - <entry>Logical Name</entry> - <entry>Type</entry> - <entry>Protectees</entry> - <entry>Dependent Functions</entry> - </row> - </thead> - - <!-- The scheduler lock --> - <tbody> - <row> - <entry>sched_lock</entry> - <entry><quote>sched lock</quote></entry> - <entry> - <constant>MTX_SPIN</constant> | - <constant>MTX_COLD</constant> - </entry> - <entry> - <varname>_gmonparam</varname>, - <varname>cnt.v_swtch</varname>, - <varname>cp_time</varname>, - <varname>curpriority</varname>, - <structname/mtx/.<structfield/mtx_blocked/, - <structname/mtx/.<structfield/mtx_contested/, - <structname/proc/.<structfield/p_contested/, - <structname/proc/.<structfield/p_blocked/, - <structname/proc/.<structfield/p_flag/ - (<constant>P_PROFIL</constant> XXX, - <constant>P_INMEM</constant>, - <constant>P_SINTR</constant>, - <constant>P_TIMEOUT</constant>, - <constant>P_SWAPINREQ</constant> XXX, - <constant>P_INMEN</constant> XXX), - <structname/proc/.<structfield/p_nice/, - <structname/proc/.<structfield/p_procq/, - <structname/proc/.<structfield/p_blocked/, - <structname/proc/.<structfield/p_estcpu/, - <structname/proc/.<structfield/p_nativepri/, - <structname/proc/.<structfield/p_priority/, - <structname/proc/.<structfield/p_usrpri/, - <structname/proc/.<structfield/p_rtprio/, - <structname/proc/.<structfield/p_rqindex/, - <structname/proc/.<structfield/p_stats->p_prof/, - <structname/proc/.<structfield/p_stats->p_ru/, - <structname/proc/.<structfield/p_stat/, - <structname/proc/.<structfield/p_cpticks/ - <structname/proc/.<structfield/p_iticks/, - <structname/proc/.<structfield/p_uticks/, - <structname/proc/.<structfield/p_sticks/, - <structname/proc/.<structfield/p_swtime/, - <structname/proc/.<structfield/p_slptime/, - <structname/proc/.<structfield/p_runtime/, - <structname/proc/.<structfield/p_pctcpu/, - <structname/proc/.<structfield/p_oncpu/, - <structname/proc/.<structfield/p_asleep/, - <structname/proc/.<structfield/p_wchan/, - <structname/proc/.<structfield/p_wmesg/, - <structname/proc/.<structfield/p_slpq/, - <structname/proc/.<structfield/p_vmspace/ - (XXX - in <function>statclock</function>), - <varname>pscnt</varname>, - <varname>slpque</varname>, - <varname>itqueuebits</varname>, - <varname>itqueues</varname>, - <varname>rtqueuebits</varname>, - <varname>rtqueues</varname>, - <varname>queuebits</varname>, - <varname>queues</varname>, - <varname>idqueuebits</varname>, - <varname>idqueues</varname>, - <varname>switchtime</varname>, - </entry> - <entry> - <function>setrunqueue</function>, - <function>remrunqueue</function>, - <function>mi_switch</function>, - <function>chooseproc</function>, - <function>schedclock</function>, - <function>resetpriority</function>, - <function>updatepri</function>, - <function>maybe_resched</function>, - <function>cpu_switch</function>, - <function>cpu_throw</function> - </entry> - </row> - - <!-- The vm86 pcb lock --> - <row> - <entry>vm86pcb_lock</entry> - <entry><quote>vm86pcb lock</quote></entry> - <entry> - <constant>MTX_DEF</constant> | - <constant>MTX_COLD</constant> - </entry> - <entry> - <varname>vm86pcb</varname> - </entry> - <entry> - <function>vm86_bioscall</function> - </entry> - </row> - - <!-- Giant --> - <row> - <entry>Giant</entry> - <entry><quote>Giant</quote></entry> - <entry> - <constant>MTX_DEF</constant> | - <constant>MTX_COLD</constant> - </entry> - <entry>nearly everything</entry> - <entry>lots</entry> - </row> - - <!-- The callout lock --> - <row> - <entry>callout_lock</entry> - <entry><quote>callout lock</quote></entry> - <entry> - <constant>MTX_SPIN</constant> - </entry> - <entry> - <varname>callfree</varname>, - <varname>callwheel</varname>, - <varname>nextsoftcheck</varname>, - <structname/proc/.<structfield/p_itcallout/, - <structname/proc/.<structfield/p_slpcallout/, - <varname>softticks</varname>, - <varname>ticks</varname> - </entry> - <entry> - </entry> - </row> - </tbody> - </tgroup> - </table> - </sect1> - - <sect1> - <title>Lock Manager Locks</title> - - <para>Locks that are provided via the &man.lockmgr.9; interface - are lock manager locks. These locks are reader-writer locks and - may be held by a sleeping process.</para> - - <table> - <title>&man.lockmgr.9; Lock List</title> - - <tgroup cols="2"> - <thead> - <row> - <entry>Variable Name</entry> - <entry>Protectees</entry> - </row> - </thead> - <tbody> - <row> - <entry><varname>allproc_lock</varname></entry> - <entry> - <varname>allproc</varname> - <varname>zombproc</varname> - <varname>pidhashtbl</varname> - <structname/proc/.<structfield/p_list/ - <structname/proc/.<structfield/p_hash/ - <varname>nextpid</varname> - </entry> - <entry><varname>proctree_lock</varname></entry> - <entry> - <structname/proc/.<structfield/p_children/ - <structname/proc/.<structfield/p_sibling/ - </entry> - </row> - </tbody> - </tgroup> - </table> - </sect1> - - <sect1> - <title>Atomically Protected Variables</title> - - <para>An atomically protected variable is a special variable that - is not protected by an explicit lock. Instead, all data - accesses to the variables use special atomic operations as - described in &man.atomic.9;. Very few variables are treated - this way, although other synchronization primitives such as - mutexes are implemented with atomically protected - variables.</para> - - <itemizedlist> - <listitem> - <para><varname>astpending</varname></para> - </listitem> - - <listitem> - <para><structname/mtx/.<structfield/mtx_lock/</para> - </listitem> - </itemizedlist> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml deleted file mode 100644 index ca94063864..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml +++ /dev/null @@ -1,372 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml,v 1.2 2001/04/09 00:33:42 dd Exp $ ---> - -<chapter id="pci"> - <title>PCI Devices</title> - - <para>This chapter will talk about the FreeBSD mechanisms for - writing a device driver for a device on a PCI bus.</para> - - <sect1> - <title>Probe and Attach</title> - - <para>Information here about how the PCI bus code iterates through - the unattached devices and see if a newly loaded kld will attach - to any of them.</para> - -<programlisting>/* - * Simple KLD to play with the PCI functions. - * - * Murray Stokely - */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> -#include <sys/bus.h> /* structs, prototypes for pci bus stuff */ - -#include <pci/pcivar.h> /* For get_pci macros! */ - -/* Function prototypes */ -d_open_t mypci_open; -d_close_t mypci_close; -d_read_t mypci_read; -d_write_t mypci_write; - -/* Character device entry points */ - -static struct cdevsw mypci_cdevsw = { - mypci_open, - mypci_close, - mypci_read, - mypci_write, - noioctl, - nopoll, - nommap, - nostrategy, - "mypci", - 36, /* reserved for lkms - /usr/src/sys/conf/majors */ - nodump, - nopsize, - D_TTY, - -1 -}; - -/* vars */ -static dev_t sdev; - -/* We're more interested in probe/attach than with - open/close/read/write at this point */ - -int -mypci_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int err = 0; - - uprintf("Opened device \"mypci\" successfully.\n"); - return(err); -} - -int -mypci_close(dev_t dev, int fflag, int devtype, struct proc *p) -{ - int err=0; - - uprintf("Closing device \"mypci.\"\n"); - return(err); -} - -int -mypci_read(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - uprintf("mypci read!\n"); - return err; -} - -int -mypci_write(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - uprintf("mypci write!\n"); - return(err); -} - -/* PCI Support Functions */ - -/* - * Return identification string if this is device is ours. - */ -static int -mypci_probe(device_t dev) -{ - uprintf("MyPCI Probe\n" - "Vendor ID : 0x%x\n" - "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev)); - - if (pci_get_vendor(dev) == 0x11c1) { - uprintf("We've got the Winmodem, probe successful!\n"); - return 0; - } - - return ENXIO; -} - -/* Attach function is only called if the probe is successful */ - -static int -mypci_attach(device_t dev) -{ - uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev)); - sdev = make_dev(<literal>&</literal>mypci_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "mypci"); - uprintf("Mypci device loaded.\n"); - return ENXIO; -} - -/* Detach device. */ - -static int -mypci_detach(device_t dev) -{ - uprintf("Mypci detach!\n"); - return 0; -} - -/* Called during system shutdown after sync. */ - -static int -mypci_shutdown(device_t dev) -{ - uprintf("Mypci shutdown!\n"); - return 0; -} - -/* - * Device suspend routine. - */ -static int -mypci_suspend(device_t dev) -{ - uprintf("Mypci suspend!\n"); - return 0; -} - -/* - * Device resume routine. - */ - -static int -mypci_resume(device_t dev) -{ - uprintf("Mypci resume!\n"); - return 0; -} - -static device_method_t mypci_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, mypci_probe), - DEVMETHOD(device_attach, mypci_attach), - DEVMETHOD(device_detach, mypci_detach), - DEVMETHOD(device_shutdown, mypci_shutdown), - DEVMETHOD(device_suspend, mypci_suspend), - DEVMETHOD(device_resume, mypci_resume), - - { 0, 0 } -}; - -static driver_t mypci_driver = { - "mypci", - mypci_methods, - 0, - /* sizeof(struct mypci_softc), */ -}; - -static devclass_t mypci_devclass; - -DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);</programlisting> - - <para>Additional Resources - <itemizedlist> - <listitem><simpara><ulink url="http://www.pcisig.org">PCI - Special Interest Group</ulink></simpara></listitem> - - <listitem><simpara>PCI System Architecture, Fourth Edition by - Tom Shanley, et al.</simpara></listitem> - - </itemizedlist> - </para> - </sect1> - - <sect1> - <title>Bus Resources</title> - - <para>FreeBSD provides an object-oriented mechanism for requesting - resources from a parent bus. Almost all devices will be a child - member of some sort of bus (PCI, ISA, USB, SCSI, etc) and these - devices need to acquire resources from their parent bus (such as - memory segments, interrupt lines, or DMA channels).</para> - - <sect2> - <title>Base Address Registers</title> - - <para>To do anything particularly useful with a PCI device you - will need to obtain the <emphasis>Base Address - Registers</emphasis> (BARs) from the PCI Configuration space. - The PCI-specific details of obtaining the BAR is abstracted in - the <function>bus_alloc_resource()</function> function.</para> - - <para>For example, a typical driver might have something similar - to this in the <function>attach()</function> function. : </para> - -<programlisting> sc->bar0id = 0x10; - sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(sc->bar0id), - 0, ~0, 1, RF_ACTIVE); - if (sc->bar0res == NULL) { - uprintf("Memory allocation of PCI base register 0 failed!\n"); - error = ENXIO; - goto fail1; - } - - sc->bar1id = 0x14; - sc->bar1res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(sc->bar1id), - 0, ~0, 1, RF_ACTIVE); - if (sc->bar1res == NULL) { - uprintf("Memory allocation of PCI base register 1 failed!\n"); - error = ENXIO; - goto fail2; - } - sc->bar0_bt = rman_get_bustag(sc->bar0res); - sc->bar0_bh = rman_get_bushandle(sc->bar0res); - sc->bar1_bt = rman_get_bustag(sc->bar1res); - sc->bar1_bh = rman_get_bushandle(sc->bar1res); - -</programlisting> - - <para>Handles for each base address register are kept in the - <structname>softc</structname> structure so that they can be - used to write to the device later.</para> - - <para>These handles can then be used to read or write from the - device registers with the <function>bus_space_*</function> - functions. For example, a driver might contain a shorthand - function to read from a board specific register like this : - </para> - -<programlisting>uint16_t -board_read(struct ni_softc *sc, uint16_t address) { - return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address); -} -</programlisting> - - <para>Similarly, one could write to the registers with : </para> - -<programlisting>void -board_write(struct ni_softc *sc, uint16_t address, uint16_t value) { - bus_space_write_2(sc->bar1_bt, sc->bar1_bh, address, value); -} -</programlisting> - - <para>These functions exist in 8bit, 16bit, and 32bit versions - and you should use - <function>bus_space_{read|write}_{1|2|4}</function> - accordingly.</para> - - </sect2> - <sect2> - <title>Interrupts</title> - - <para>Interrupts are allocated from the object-oriented bus code - in a way similar to the memory resources. First an IRQ - resource must be allocated from the parent bus, and then the - interrupt handler must be setup to deal with this IRQ.</para> - - <para>Again, a sample from a device - <function>attach()</function> function says more than - words.</para> - -<programlisting>/* Get the IRQ resource */ - - sc->irqid = 0x0; - sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &(sc->irqid), - 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); - if (sc->irqres == NULL) { - uprintf("IRQ allocation failed!\n"); - error = ENXIO; - goto fail3; - } - - /* Now we should setup the interrupt handler */ - - error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_MISC, - my_handler, sc, &(sc->handler)); - if (error) { - printf("Couldn't set up irq\n"); - goto fail4; - } - - sc->irq_bt = rman_get_bustag(sc->irqres); - sc->irq_bh = rman_get_bushandle(sc->irqres); -</programlisting> - - </sect2> - - <sect2> - <title>DMA</title> - <para>On the PC, peripherals that want to do bus-mastering DMA - must deal with physical addresses. This is a problem since - FreeBSD uses virtual memory and deals almost exclusively with - virtual addresses. Fortunately, there is a function, - <function>vtophys()</function> to help.</para> - -<programlisting>#include <vm/vm.h> -#include <vm/pmap.h> - -#define vtophys(virtual_address) (...) -</programlisting> - - <para>The solution is a bit different on the alpha however, and - what we really want is a function called - <function>vtobus()</function>.</para> - -<programlisting>#if defined(__alpha__) -#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va) -#else -#define vtobus(va) vtophys(va) -#endif -</programlisting> - - </sect2> - - <sect2> - <title>Deallocating Resources</title> - - <para>It's very important to deallocate all of the resources - that were allocated during <function>attach()</function>. - Care must be taken to deallocate the correct stuff even on a - failure condition so that the system will remain useable while - your driver dies.</para> - - </sect2> - </sect1> - -</chapter> - - diff --git a/en_US.ISO8859-1/books/arch-handbook/scsi/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/scsi/chapter.sgml deleted file mode 100644 index 072aea5499..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/scsi/chapter.sgml +++ /dev/null @@ -1,1983 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/developers-handbook/scsi/chapter.sgml,v 1.4 2001/06/13 11:35:56 tom Exp $ ---> - -<chapter id="scsi"> - <title>Common Access Method SCSI Controllers</title> - - <para><emphasis>This chapter was written by &a.babkin; - Modifications for the handbook made by - &a.murray;.</emphasis></para> - - <sect1> - <title>Synopsis</title> - - <para>This document assumes that the reader has a general - understanding of device drivers in FreeBSD and of the SCSI - protocol. Much of the information in this document was - extracted from the drivers :</para> - - <itemizedlist> - - <listitem><para>ncr (<filename>/sys/pci/ncr.c</filename>) by - Wolfgang Stanglmeier and Stefan Esser</para></listitem> - - <listitem><para>sym (<filename>/sys/pci/sym.c</filename>) by - Gerard Roudier</para></listitem> - - <listitem><para>aic7xxx - (<filename>/sys/dev/aic7xxx/aic7xxx.c</filename>) by Justin - T. Gibbs</para></listitem> - - </itemizedlist> - - <para>and from the CAM code itself (by Justing T. Gibbs, see - <filename>/sys/cam/*</filename>). When some solution looked the - most logical and was essentially verbatim extracted from the code - by Justin Gibbs, I marked it as "recommended".</para> - - <para>The document is illustrated with examples in - pseudo-code. Although sometimes the examples have many details - and look like real code, it's still pseudo-code. It was written - to demonstrate the concepts in an understandable way. For a real - driver other approaches may be more modular and efficient. It - also abstracts from the hardware details, as well as issues that - would cloud the demonstrated concepts or that are supposed to be - described in the other chapters of the developers handbook. Such - details are commonly shown as calls to functions with descriptive - names, comments or pseudo-statements. Fortunately real life - full-size examples with all the details can be found in the real - drivers.</para> - - </sect1> - - <sect1> - <title>General architecture</title> - - <para>CAM stands for Common Access Method. It's a generic way to - address the I/O buses in a SCSI-like way. This allows a - separation of the generic device drivers from the drivers - controlling the I/O bus: for example the disk driver becomes able - to control disks on both SCSI, IDE, and/or any other bus so the - disk driver portion does not have to be rewritten (or copied and - modified) for every new I/O bus. Thus the two most important - active entities are:</para> - - <itemizedlist> - <listitem><para><emphasis>Peripheral Modules</emphasis> - a - driver for peripheral devices (disk, tape, CDROM, - etc.)</para></listitem> - <listitem><para><emphasis>SCSI Interface Modules </emphasis>(SIM) - - a Host Bus Adapter drivers for connecting to an I/O bus such - as SCSI or IDE.</para></listitem> - </itemizedlist> - - <para>A peripheral driver receives requests from the OS, converts - them to a sequence of SCSI commands and passes these SCSI - commands to a SCSI Interface Module. The SCSI Interface Module - is responsible for passing these commands to the actual hardware - (or if the actual hardware is not SCSI but, for example, IDE - then also converting the SCSI commands to the native commands of - the hardware).</para> - - <para>Because we are interested in writing a SCSI adapter driver - here, from this point on we will consider everything from the - SIM standpoint.</para> - - <para>A typical SIM driver needs to include the following - CAM-related header files:</para> - -<programlisting>#include <cam/cam.h> -#include <cam/cam_ccb.h> -#include <cam/cam_sim.h> -#include <cam/cam_xpt_sim.h> -#include <cam/cam_debug.h> -#include <cam/scsi/scsi_all.h></programlisting> - - <para>The first thing each SIM driver must do is register itself - with the CAM subsystem. This is done during the driver's - <function>xxx_attach()</function> function (here and further - xxx_ is used to denote the unique driver name prefix). The - <function>xxx_attach()</function> function itself is called by - the system bus auto-configuration code which we don't describe - here.</para> - - <para>This is achieved in multiple steps: first it's necessary to - allocate the queue of requests associated with this SIM:</para> - -<programlisting> struct cam_devq *devq; - - if(( devq = cam_simq_alloc(SIZE) )==NULL) { - error; /* some code to handle the error */ - }</programlisting> - - <para>Here SIZE is the size of the queue to be allocated, maximal - number of requests it could contain. It's the number of requests - that the SIM driver can handle in parallel on one SCSI - card. Commonly it can be calculated as:</para> - -<programlisting>SIZE = NUMBER_OF_SUPPORTED_TARGETS * MAX_SIMULTANEOUS_COMMANDS_PER_TARGET</programlisting> - - <para>Next we create a descriptor of our SIM:</para> - -<programlisting> struct cam_sim *sim; - - if(( sim = cam_sim_alloc(action_func, poll_func, driver_name, - softc, unit, max_dev_transactions, - max_tagged_dev_transactions, devq) )==NULL) { - cam_simq_free(devq); - error; /* some code to handle the error */ - }</programlisting> - - <para>Note that if we are not able to create a SIM descriptor we - free the <structname>devq</structname> also because we can do - nothing else with it and we want to conserve memory.</para> - - <para>If a SCSI card has multiple SCSI buses on it then each bus - requires its own <structname>cam_sim</structname> - structure.</para> - - <para>An interesting question is what to do if a SCSI card has - more than one SCSI bus, do we need one - <structname>devq</structname> structure per card or per SCSI - bus? The answer given in the comments to the CAM code is: - either way, as the driver's author prefers.</para> - - <para>The arguments are : - <itemizedlist> - - <listitem><para><function>action_func</function> - pointer to - the driver's <function>xxx_action</function> function. - <funcSynopsis><funcPrototype> - <funcDef>static void - <function>xxx_action</function> - </funcDef> - <paramdef> - <parameter>struct cam_sim *sim</parameter>, - <parameter>union ccb *ccb</parameter> - </paramdef> - </funcPrototype></funcSynopsis> - </para></listitem> - - <listitem><para><function>poll_func</function> - pointer to - the driver's <function>xxx_poll()</function> - <funcSynopsis><funcPrototype> - <funcDef>static void - <function>xxx_poll</function> - </funcDef> - <paramdef> - <parameter>struct cam_sim *sim</parameter> - </paramdef> - </funcPrototype></funcSynopsis> - </para></listitem> - - <listitem><para>driver_name - the name of the actual driver, - such as "ncr" or "wds"</para></listitem> - - <listitem><para><structName>softc</structName> - pointer to the - driver's internal descriptor for this SCSI card. This - pointer will be used by the driver in future to get private - data.</para></listitem> - - <listitem><para>unit - the controller unit number, for example - for controller "wds0" this number will be - 0</para></listitem> - - <listitem><para>max_dev_transactions - maximal number of - simultaneous transactions per SCSI target in the non-tagged - mode. This value will be almost universally equal to 1, with - possible exceptions only for the non-SCSI cards. Also the - drivers that hope to take advantage by preparing one - transaction while another one is executed may set it to 2 - but this does not seem to be worth the - complexity.</para></listitem> - - <listitem><para>max_tagged_dev_transactions - the same thing, - but in the tagged mode. Tags are the SCSI way to initiate - multiple transactions on a device: each transaction is - assigned a unique tag and the transaction is sent to the - device. When the device completes some transaction it sends - back the result together with the tag so that the SCSI - adapter (and the driver) can tell which transaction was - completed. This argument is also known as the maximal tag - depth. It depends on the abilities of the SCSI - adapter.</para></listitem> - </itemizedlist> - </para> - - <para>Finally we register the SCSI buses associated with our SCSI - adapter:</para> - -<programlisting> if(xpt_bus_register(sim, bus_number) != CAM_SUCCESS) { - cam_sim_free(sim, /*free_devq*/ TRUE); - error; /* some code to handle the error */ - }</programlisting> - - <para>If there is one <structName>devq</structName> structure per - SCSI bus (i.e. we consider a card with multiple buses as - multiple cards with one bus each) then the bus number will - always be 0, otherwise each bus on the SCSI card should be get a - distinct number. Each bus needs its own separate structure - cam_sim.</para> - - <para>After that our controller is completely hooked to the CAM - system. The value of <structName>devq</structName> can be - discarded now: sim will be passed as an argument in all further - calls from CAM and devq can be derived from it.</para> - - <para>CAM provides the framework for such asynchronous - events. Some events originate from the lower levels (the SIM - drivers), some events originate from the peripheral drivers, - some events originate from the CAM subsystem itself. Any driver - can register callbacks for some types of the asynchronous - events, so that it would be notified if these events - occur.</para> - - <para>A typical example of such an event is a device reset. Each - transaction and event identifies the devices to which it applies - by the means of "path". The target-specific events normally - occur during a transaction with this device. So the path from - that transaction may be re-used to report this event (this is - safe because the event path is copied in the event reporting - routine but not deallocated nor passed anywhere further). Also - it's safe to allocate paths dynamically at any time including - the interrupt routines, although that incurs certain overhead, - and a possible problem with this approach is that there may be - no free memory at that time. For a bus reset event we need to - define a wildcard path including all devices on the bus. So we - can create the path for the future bus reset events in advance - and avoid problems with the future memory shortage:</para> - -<programlisting> struct cam_path *path; - - if(xpt_create_path(&path, /*periph*/NULL, - cam_sim_path(sim), CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD) != CAM_REQ_CMP) { - xpt_bus_deregister(cam_sim_path(sim)); - cam_sim_free(sim, /*free_devq*/TRUE); - error; /* some code to handle the error */ - } - - softc->wpath = path; - softc->sim = sim;</programlisting> - - <para>As you can see the path includes:</para> - - <itemizedlist> - <listitem><para>ID of the peripheral driver (NULL here because we have - none)</para></listitem> - - <listitem><para>ID of the SIM driver - (<function>cam_sim_path(sim)</function>)</para></listitem> - - <listitem><para>SCSI target number of the device (CAM_TARGET_WILDCARD - means "all devices")</para></listitem> - - <listitem><para>SCSI LUN number of the subdevice (CAM_LUN_WILDCARD means - "all LUNs")</para></listitem> - </itemizedlist> - - <para>If the driver can't allocate this path it won't be able to - work normally, so in that case we dismantle that SCSI - bus.</para> - - <para>And we save the path pointer in the - <structName>softc</structName> structure for future use. After - that we save the value of sim (or we can also discard it on the - exit from <function>xxx_probe()</function> if we wish).</para> - - <para>That's all for a minimalistic initialization. To do things - right there is one more issue left. </para> - - <para>For a SIM driver there is one particularly interesting - event: when a target device is considered lost. In this case - resetting the SCSI negotiations with this device may be a good - idea. So we register a callback for this event with CAM. The - request is passed to CAM by requesting CAM action on a CAM - control block for this type of request:</para> - -<programlisting> struct ccb_setasync csa; - - xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5); - csa.ccb_h.func_code = XPT_SASYNC_CB; - csa.event_enable = AC_LOST_DEVICE; - csa.callback = xxx_async; - csa.callback_arg = sim; - xpt_action((union ccb *)&csa);</programlisting> - - <para>Now we take a look at the <function>xxx_action()</function> - and <function>xxx_poll()</function> driver entry points.</para> - - <para> - <funcSynopsis><funcPrototype> - <funcDef>static void - <function>xxx_action</function> - </funcDef> - <paramdef> - <parameter>struct cam_sim *sim</parameter>, - <parameter>union ccb *ccb</parameter> - </paramdef> - </funcPrototype></funcSynopsis> - </para> - - <para>Do some action on request of the CAM subsystem. Sim - describes the SIM for the request, CCB is the request - itself. CCB stands for "CAM Control Block". It is a union of - many specific instances, each describing arguments for some type - of transactions. All of these instances share the CCB header - where the common part of arguments is stored.</para> - - <para>CAM supports the SCSI controllers working in both initiator - ("normal") mode and target (simulating a SCSI device) mode. Here - we only consider the part relevant to the initiator mode.</para> - - <para>There are a few function and macros (in other words, - methods) defined to access the public data in the struct sim:</para> - - <itemizedlist> - <listitem><para><function>cam_sim_path(sim)</function> - the - path ID (see above)</para></listitem> - - <listitem><para><function>cam_sim_name(sim)</function> - the - name of the sim</para></listitem> - - <listitem><para><function>cam_sim_softc(sim)</function> - the - pointer to the softc (driver private data) - structure</para></listitem> - - <listitem><para><function> cam_sim_unit(sim)</function> - the - unit number</para></listitem> - - <listitem><para><function> cam_sim_bus(sim)</function> - the bus - ID</para></listitem> - </itemizedlist> - - <para>To identify the device, <function>xxx_action()</function> can - get the unit number and pointer to its structure softc using - these functions.</para> - - <para>The type of request is stored in - <structField>ccb->ccb_h.func_code</structField>. So generally - <function>xxx_action()</function> consists of a big - switch:</para> - -<programlisting> struct xxx_softc *softc = (struct xxx_softc *) cam_sim_softc(sim); - struct ccb_hdr *ccb_h = &ccb->ccb_h; - int unit = cam_sim_unit(sim); - int bus = cam_sim_bus(sim); - - switch(ccb_h->func_code) { - case ...: - ... - default: - ccb_h->status = CAM_REQ_INVALID; - xpt_done(ccb); - break; - }</programlisting> - - <para>As can be seen from the default case (if an unknown command - was received) the return code of the command is set into - <structField>ccb->ccb_h.status</structField> and the completed - CCB is returned back to CAM by calling - <function>xpt_done(ccb)</function>. </para> - - <para><function>xpt_done()</function> does not have to be called - from <function>xxx_action()</function>: For example an I/O - request may be enqueued inside the SIM driver and/or its SCSI - controller. Then when the device would post an interrupt - signaling that the processing of this request is complete - <function>xpt_done()</function> may be called from the interrupt - handling routine.</para> - - <para>Actually, the CCB status is not only assigned as a return - code but a CCB has some status all the time. Before CCB is - passed to the <function>xxx_action()</function> routine it gets - the status CCB_REQ_INPROG meaning that it's in progress. There - are a surprising number of status values defined in - <filename>/sys/cam/cam.h</filename> which should be able to - represent the status of a request in great detail. More - interesting yet, the status is in fact a "bitwise or" of an - enumerated status value (the lower 6 bits) and possible - additional flag-like bits (the upper bits). The enumerated - values will be discussed later in more detail. The summary of - them can be found in the Errors Summary section. The possible - status flags are:</para> - - <itemizedlist> - - <listitem><para><emphasis>CAM_DEV_QFRZN</emphasis> - if the - SIM driver gets a serious error (for example, the device does - not respond to the selection or breaks the SCSI protocol) when - processing a CCB it should freeze the request queue by calling - <function>xpt_freeze_simq()</function>, return the other - enqueued but not processed yet CCBs for this device back to - the CAM queue, then set this flag for the troublesome CCB and - call <function>xpt_done()</function>. This flag causes the CAM - subsystem to unfreeze the queue after it handles the - error.</para></listitem> - - <listitem><para><emphasis>CAM_AUTOSNS_VALID</emphasis> - if - the device returned an error condition and the flag - CAM_DIS_AUTOSENSE is not set in CCB the SIM driver must - execute the REQUEST SENSE command automatically to extract the - sense (extended error information) data from the device. If - this attempt was successful the sense data should be saved in - the CCB and this flag set.</para></listitem> - - <listitem><para><emphasis>CAM_RELEASE_SIMQ</emphasis> - like - CAM_DEV_QFRZN but used in case there is some problem (or - resource shortage) with the SCSI controller itself. Then all - the future requests to the controller should be stopped by - <function>xpt_freeze_simq()</function>. The controller queue - will be restarted after the SIM driver overcomes the shortage - and informs CAM by returning some CCB with this flag - set.</para></listitem> - - <listitem><para><emphasis>CAM_SIM_QUEUED</emphasis> - when SIM - puts a CCB into its request queue this flag should be set (and - removed when this CCB gets dequeued before being returned back - to CAM). This flag is not used anywhere in the CAM code now, - so its purpose is purely diagnostic.</para></listitem> - - </itemizedlist> - - <para>The function <function>xxx_action()</function> is not - allowed to sleep, so all the synchronization for resource access - must be done using SIM or device queue freezing. Besides the - aforementioned flags the CAM subsystem provides functions - <function>xpt_selease_simq()</function> and - <function>xpt_release_devq()</function> to unfreeze the queues - directly, without passing a CCB to CAM.</para> - - <para>The CCB header contains the following fields:</para> - - <itemizedlist> - - <listitem><para><emphasis>path</emphasis> - path ID for the - request</para></listitem> - - <listitem><para><emphasis>target_id</emphasis> - target device - ID for the request</para></listitem> - - <listitem><para><emphasis>target_lun</emphasis> - LUN ID of - the target device</para></listitem> - - <listitem><para><emphasis>timeout</emphasis> - timeout - interval for this command, in milliseconds</para></listitem> - - <listitem><para><emphasis>timeout_ch</emphasis> - a - convenience place for the SIM driver to store the timeout handle - (the CAM subsystem itself does not make any assumptions about - it)</para></listitem> - - <listitem><para><emphasis>flags</emphasis> - various bits of - information about the request spriv_ptr0, spriv_ptr1 - fields - reserved for private use by the SIM driver (such as linking to - the SIM queues or SIM private control blocks); actually, they - exist as unions: spriv_ptr0 and spriv_ptr1 have the type (void - *), spriv_field0 and spriv_field1 have the type unsigned long, - sim_priv.entries[0].bytes and sim_priv.entries[1].bytes are byte - arrays of the size consistent with the other incarnations of the - union and sim_priv.bytes is one array, twice - bigger.</para></listitem> - - </itemizedlist> - - <para>The recommended way of using the SIM private fields of CCB - is to define some meaningful names for them and use these - meaningful names in the driver, like:</para> - -<programlisting>#define ccb_some_meaningful_name sim_priv.entries[0].bytes -#define ccb_hcb spriv_ptr1 /* for hardware control block */</programlisting> - - <para>The most common initiator mode requests are:</para> - <itemizedlist> - <listitem><para><emphasis>XPT_SCSI_IO</emphasis> - execute an - I/O transaction</para> - - <para>The instance "struct ccb_scsiio csio" of the union ccb is - used to transfer the arguments. They are:</para> - - <itemizedlist> - <listitem><para><emphasis>cdb_io</emphasis> - pointer to - the SCSI command buffer or the buffer - itself</para></listitem> - - <listitem><para><emphasis>cdb_len</emphasis> - SCSI - command length</para></listitem> - - <listitem><para><emphasis>data_ptr</emphasis> - pointer to - the data buffer (gets a bit complicated if scatter/gather is - used)</para></listitem> - - <listitem><para><emphasis>dxfer_len</emphasis> - length of - the data to transfer</para></listitem> - - <listitem><para><emphasis>sglist_cnt</emphasis> - counter - of the scatter/gather segments</para></listitem> - - <listitem><para><emphasis>scsi_status</emphasis> - place - to return the SCSI status</para></listitem> - - <listitem><para><emphasis>sense_data</emphasis> - buffer - for the SCSI sense information if the command returns an - error (the SIM driver is supposed to run the REQUEST SENSE - command automatically in this case if the CCB flag - CAM_DIS_AUTOSENSE is not set)</para></listitem> - - <listitem><para><emphasis>sense_len</emphasis> - the - length of that buffer (if it happens to be higher than size - of sense_data the SIM driver must silently assume the - smaller value) resid, sense_resid - if the transfer of data - or SCSI sense returned an error these are the returned - counters of the residual (not transferred) data. They do not - seem to be especially meaningful, so in a case when they are - difficult to compute (say, counting bytes in the SCSI - controller's FIFO buffer) an approximate value will do as - well. For a successfully completed transfer they must be set - to zero.</para></listitem> - - <listitem><para><emphasis>tag_action</emphasis> - the kind - of tag to use: - - <itemizedlist> - <listitem><para>CAM_TAG_ACTION_NONE - don't use tags for this - transaction</para></listitem> - <listitem><para>MSG_SIMPLE_Q_TAG, MSG_HEAD_OF_Q_TAG, - MSG_ORDERED_Q_TAG - value equal to the appropriate tag - message (see /sys/cam/scsi/scsi_message.h); this gives only - the tag type, the SIM driver must assign the tag value - itself</para></listitem> - </itemizedlist> - - </para></listitem> - - </itemizedlist> - - <para>The general logic of handling this request is the - following:</para> - - <para>The first thing to do is to check for possible races, to - make sure that the command did not get aborted when it was - sitting in the queue:</para> - -<programlisting> struct ccb_scsiio *csio = &ccb->csio; - - if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { - xpt_done(ccb); - return; - }</programlisting> - - <para>Also we check that the device is supported at all by our - controller:</para> - -<programlisting> if(ccb_h->target_id > OUR_MAX_SUPPORTED_TARGET_ID - || cch_h->target_id == OUR_SCSI_CONTROLLERS_OWN_ID) { - ccb_h->status = CAM_TID_INVALID; - xpt_done(ccb); - return; - } - if(ccb_h->target_lun > OUR_MAX_SUPPORTED_LUN) { - ccb_h->status = CAM_LUN_INVALID; - xpt_done(ccb); - return; - }</programlisting> - - <para>Then allocate whatever data structures (such as - card-dependent hardware control block) we need to process this - request. If we can't then freeze the SIM queue and remember - that we have a pending operation, return the CCB back and ask - CAM to re-queue it. Later when the resources become available - the SIM queue must be unfrozen by returning a ccb with the - CAM_SIMQ_RELEASE bit set in its status. Otherwise, if all went - well, link the CCB with the hardware control block (HCB) and - mark it as queued.</para> - -<programlisting> struct xxx_hcb *hcb = allocate_hcb(softc, unit, bus); - - if(hcb == NULL) { - softc->flags |= RESOURCE_SHORTAGE; - xpt_freeze_simq(sim, /*count*/1); - ccb_h->status = CAM_REQUEUE_REQ; - xpt_done(ccb); - return; - } - - hcb->ccb = ccb; ccb_h->ccb_hcb = (void *)hcb; - ccb_h->status |= CAM_SIM_QUEUED;</programlisting> - - <para>Extract the target data from CCB into the hardware control - block. Check if we are asked to assign a tag and if yes then - generate an unique tag and build the SCSI tag messages. The - SIM driver is also responsible for negotiations with the - devices to set the maximal mutually supported bus width, - synchronous rate and offset.</para> - -<programlisting> hcb->target = ccb_h->target_id; hcb->lun = ccb_h->target_lun; - generate_identify_message(hcb); - if( ccb_h->tag_action != CAM_TAG_ACTION_NONE ) - generate_unique_tag_message(hcb, ccb_h->tag_action); - if( !target_negotiated(hcb) ) - generate_negotiation_messages(hcb);</programlisting> - - <para>Then set up the SCSI command. The command storage may be - specified in the CCB in many interesting ways, specified by - the CCB flags. The command buffer can be contained in CCB or - pointed to, in the latter case the pointer may be physical or - virtual. Since the hardware commonly needs physical address we - always convert the address to the physical one.</para> - - <para>A NOT-QUITE RELATED NOTE: Normally this is done by a call - to vtophys(), but for the PCI device (which account for most - of the SCSI controllers now) drivers' portability to the Alpha - architecture the conversion must be done by vtobus() instead - due to special Alpha quirks. [IMHO it would be much better to - have two separate functions, vtop() and ptobus() then vtobus() - would be a simple superposition of them.] In case if a - physical address is requested it's OK to return the CCB with - the status CAM_REQ_INVALID, the current drivers do that. But - it's also possible to compile the Alpha-specific piece of - code, as in this example (there should be a more direct way to - do that, without conditional compilation in the drivers). If - necessary a physical address can be also converted or mapped - back to a virtual address but with big pain, so we don't do - that.</para> - -<programlisting> if(ccb_h->flags & CAM_CDB_POINTER) { - /* CDB is a pointer */ - if(!(ccb_h->flags & CAM_CDB_PHYS)) { - /* CDB pointer is virtual */ - hcb->cmd = vtobus(csio->cdb_io.cdb_ptr); - } else { - /* CDB pointer is physical */ -#if defined(__alpha__) - hcb->cmd = csio->cdb_io.cdb_ptr | alpha_XXX_dmamap_or ; -#else - hcb->cmd = csio->cdb_io.cdb_ptr ; -#endif - } - } else { - /* CDB is in the ccb (buffer) */ - hcb->cmd = vtobus(csio->cdb_io.cdb_bytes); - } - hcb->cmdlen = csio->cdb_len;</programlisting> - - <para>Now it's time to set up the data. Again, the data storage - may be specified in the CCB in many interesting ways, - specified by the CCB flags. First we get the direction of the - data transfer. The simplest case is if there is no data to - transfer:</para> - -<programlisting> int dir = (ccb_h->flags & CAM_DIR_MASK); - - if (dir == CAM_DIR_NONE) - goto end_data;</programlisting> - - <para>Then we check if the data is in one chunk or in a - scatter-gather list, and the addresses are physical or - virtual. The SCSI controller may be able to handle only a - limited number of chunks of limited length. If the request - hits this limitation we return an error. We use a special - function to return the CCB to handle in one place the HCB - resource shortages. The functions to add chunks are - driver-dependent, and here we leave them without detailed - implementation. See description of the SCSI command (CDB) - handling for the details on the address-translation issues. - If some variation is too difficult or impossible to implement - with a particular card it's OK to return the status - CAM_REQ_INVALID. Actually, it seems like the scatter-gather - ability is not used anywhere in the CAM code now. But at least - the case for a single non-scattered virtual buffer must be - implemented, it's actively used by CAM.</para> - -<programlisting> int rv; - - initialize_hcb_for_data(hcb); - - if((!(ccb_h->flags & CAM_SCATTER_VALID)) { - /* single buffer */ - if(!(ccb_h->flags & CAM_DATA_PHYS)) { - rv = add_virtual_chunk(hcb, csio->data_ptr, csio->dxfer_len, dir); - } - } else { - rv = add_physical_chunk(hcb, csio->data_ptr, csio->dxfer_len, dir); - } - } else { - int i; - struct bus_dma_segment *segs; - segs = (struct bus_dma_segment *)csio->data_ptr; - - if ((ccb_h->flags & CAM_SG_LIST_PHYS) != 0) { - /* The SG list pointer is physical */ - rv = setup_hcb_for_physical_sg_list(hcb, segs, csio->sglist_cnt); - } else if (!(ccb_h->flags & CAM_DATA_PHYS)) { - /* SG buffer pointers are virtual */ - for (i = 0; i < csio->sglist_cnt; i++) { - rv = add_virtual_chunk(hcb, segs[i].ds_addr, - segs[i].ds_len, dir); - if (rv != CAM_REQ_CMP) - break; - } - } else { - /* SG buffer pointers are physical */ - for (i = 0; i < csio->sglist_cnt; i++) { - rv = add_physical_chunk(hcb, segs[i].ds_addr, - segs[i].ds_len, dir); - if (rv != CAM_REQ_CMP) - break; - } - } - } - if(rv != CAM_REQ_CMP) { - /* we expect that add_*_chunk() functions return CAM_REQ_CMP - * if they added a chunk successfully, CAM_REQ_TOO_BIG if - * the request is too big (too many bytes or too many chunks), - * CAM_REQ_INVALID in case of other troubles - */ - free_hcb_and_ccb_done(hcb, ccb, rv); - return; - } - end_data:</programlisting> - - <para>If disconnection is disabled for this CCB we pass this - information to the hcb:</para> - -<programlisting> if(ccb_h->flags & CAM_DIS_DISCONNECT) - hcb_disable_disconnect(hcb);</programlisting> - - <para>If the controller is able to run REQUEST SENSE command all - by itself then the value of the flag CAM_DIS_AUTOSENSE should - also be passed to it, to prevent automatic REQUEST SENSE if the - CAM subsystem does not want it.</para> - - <para>The only thing left is to set up the timeout, pass our hcb - to the hardware and return, the rest will be done by the - interrupt handler (or timeout handler).</para> - -<programlisting> ccb_h->timeout_ch = timeout(xxx_timeout, (caddr_t) hcb, - (ccb_h->timeout * hz) / 1000); /* convert milliseconds to ticks */ - put_hcb_into_hardware_queue(hcb); - return;</programlisting> - - <para>And here is a possible implementation of the function - returning CCB:</para> - -<programlisting> static void - free_hcb_and_ccb_done(struct xxx_hcb *hcb, union ccb *ccb, u_int32_t status) - { - struct xxx_softc *softc = hcb->softc; - - ccb->ccb_h.ccb_hcb = 0; - if(hcb != NULL) { - untimeout(xxx_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); - /* we're about to free a hcb, so the shortage has ended */ - if(softc->flags & RESOURCE_SHORTAGE) { - softc->flags &= ~RESOURCE_SHORTAGE; - status |= CAM_RELEASE_SIMQ; - } - free_hcb(hcb); /* also removes hcb from any internal lists */ - } - ccb->ccb_h.status = status | - (ccb->ccb_h.status & ~(CAM_STATUS_MASK|CAM_SIM_QUEUED)); - xpt_done(ccb); - }</programlisting> - </listitem> - - <listitem><para><emphasis>XPT_RESET_DEV</emphasis> - send the SCSI "BUS - DEVICE RESET" message to a device</para> - - <para>There is no data transferred in CCB except the header and - the most interesting argument of it is target_id. Depending on - the controller hardware a hardware control block just like for - the XPT_SCSI_IO request may be constructed (see XPT_SCSI_IO - request description) and sent to the controller or the SCSI - controller may be immediately programmed to send this RESET - message to the device or this request may be just not supported - (and return the status CAM_REQ_INVALID). Also on completion of - the request all the disconnected transactions for this target - must be aborted (probably in the interrupt routine).</para> - - <para>Also all the current negotiations for the target are lost on - reset, so they might be cleaned too. Or they clearing may be - deferred, because anyway the target would request re-negotiation - on the next transaction.</para></listitem> - - <listitem><para><emphasis>XPT_RESET_BUS</emphasis> - send the RESET signal - to the SCSI bus</para> - - <para>No arguments are passed in the CCB, the only interesting - argument is the SCSI bus indicated by the struct sim - pointer.</para> - - <para>A minimalistic implementation would forget the SCSI - negotiations for all the devices on the bus and return the - status CAM_REQ_CMP.</para> - - <para>The proper implementation would in addition actually reset - the SCSI bus (possible also reset the SCSI controller) and mark - all the CCBs being processed, both those in the hardware queue - and those being disconnected, as done with the status - CAM_SCSI_BUS_RESET. Like:</para> - -<programlisting> int targ, lun; - struct xxx_hcb *h, *hh; - struct ccb_trans_settings neg; - struct cam_path *path; - - /* The SCSI bus reset may take a long time, in this case its completion - * should be checked by interrupt or timeout. But for simplicity - * we assume here that it's really fast. - */ - reset_scsi_bus(softc); - - /* drop all enqueued CCBs */ - for(h = softc->first_queued_hcb; h != NULL; h = hh) { - hh = h->next; - free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET); - } - - /* the clean values of negotiations to report */ - neg.bus_width = 8; - neg.sync_period = neg.sync_offset = 0; - neg.valid = (CCB_TRANS_BUS_WIDTH_VALID - | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID); - - /* drop all disconnected CCBs and clean negotiations */ - for(targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) { - clean_negotiations(softc, targ); - - /* report the event if possible */ - if(xpt_create_path(&path, /*periph*/NULL, - cam_sim_path(sim), targ, - CAM_LUN_WILDCARD) == CAM_REQ_CMP) { - xpt_async(AC_TRANSFER_NEG, path, &neg); - xpt_free_path(path); - } - - for(lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++) - for(h = softc->first_discon_hcb[targ][lun]; h != NULL; h = hh) { - hh=h->next; - free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET); - } - } - - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - - /* report the event */ - xpt_async(AC_BUS_RESET, softc->wpath, NULL); - return;</programlisting> - - <para>Implementing the SCSI bus reset as a function may be a good - idea because it would be re-used by the timeout function as a - last resort if the things go wrong.</para></listitem> - - <listitem><para><emphasis>XPT_ABORT</emphasis> - abort the specified - CCB</para> - - <para>The arguments are transferred in the instance "struct - ccb_abort cab" of the union ccb. The only argument field in it - is:</para> - - <para><emphasis>abort_ccb</emphasis> - pointer to the CCB to be - aborted</para> - - <para>If the abort is not supported just return the status - CAM_UA_ABORT. This is also the easy way to minimally implement - this call, return CAM_UA_ABORT in any case.</para> - - <para>The hard way is to implement this request honestly. First - check that abort applies to a SCSI transaction:</para> - -<programlisting> struct ccb *abort_ccb; - abort_ccb = ccb->cab.abort_ccb; - - if(abort_ccb->ccb_h.func_code != XPT_SCSI_IO) { - ccb->ccb_h.status = CAM_UA_ABORT; - xpt_done(ccb); - return; - }</programlisting> - - <para>Then it's necessary to find this CCB in our queue. This can - be done by walking the list of all our hardware control blocks - in search for one associated with this CCB:</para> - -<programlisting> struct xxx_hcb *hcb, *h; - - hcb = NULL; - - /* We assume that softc->first_hcb is the head of the list of all - * HCBs associated with this bus, including those enqueued for - * processing, being processed by hardware and disconnected ones. - */ - for(h = softc->first_hcb; h != NULL; h = h->next) { - if(h->ccb == abort_ccb) { - hcb = h; - break; - } - } - - if(hcb == NULL) { - /* no such CCB in our queue */ - ccb->ccb_h.status = CAM_PATH_INVALID; - xpt_done(ccb); - return; - } - - hcb=found_hcb;</programlisting> - - <para>Now we look at the current processing status of the HCB. It - may be either sitting in the queue waiting to be sent to the - SCSI bus, being transferred right now, or disconnected and - waiting for the result of the command, or actually completed by - hardware but not yet marked as done by software. To make sure - that we don't get in any races with hardware we mark the HCB as - being aborted, so that if this HCB is about to be sent to the - SCSI bus the SCSI controller will see this flag and skip - it.</para> - -<programlisting> int hstatus; - - /* shown as a function, in case special action is needed to make - * this flag visible to hardware - */ - set_hcb_flags(hcb, HCB_BEING_ABORTED); - - abort_again: - - hstatus = get_hcb_status(hcb); - switch(hstatus) { - case HCB_SITTING_IN_QUEUE: - remove_hcb_from_hardware_queue(hcb); - /* FALLTHROUGH */ - case HCB_COMPLETED: - /* this is an easy case */ - free_hcb_and_ccb_done(hcb, abort_ccb, CAM_REQ_ABORTED); - break;</programlisting> - - <para>If the CCB is being transferred right now we would like to - signal to the SCSI controller in some hardware-dependent way - that we want to abort the current transfer. The SCSI controller - would set the SCSI ATTENTION signal and when the target responds - to it send an ABORT message. We also reset the timeout to make - sure that the target is not sleeping forever. If the command - would not get aborted in some reasonable time like 10 seconds - the timeout routine would go ahead and reset the whole SCSI bus. - Because the command will be aborted in some reasonable time we - can just return the abort request now as successfully completed, - and mark the aborted CCB as aborted (but not mark it as done - yet).</para> - -<programlisting> case HCB_BEING_TRANSFERRED: - untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch); - abort_ccb->ccb_h.timeout_ch = - timeout(xxx_timeout, (caddr_t) hcb, 10 * hz); - abort_ccb->ccb_h.status = CAM_REQ_ABORTED; - /* ask the controller to abort that HCB, then generate - * an interrupt and stop - */ - if(signal_hardware_to_abort_hcb_and_stop(hcb) < 0) { - /* oops, we missed the race with hardware, this transaction - * got off the bus before we aborted it, try again */ - goto abort_again; - } - - break;</programlisting> - - <para>If the CCB is in the list of disconnected then set it up as - an abort request and re-queue it at the front of hardware - queue. Reset the timeout and report the abort request to be - completed.</para> - -<programlisting> case HCB_DISCONNECTED: - untimeout(xxx_timeout, (caddr_t) hcb, abort_ccb->ccb_h.timeout_ch); - abort_ccb->ccb_h.timeout_ch = - timeout(xxx_timeout, (caddr_t) hcb, 10 * hz); - put_abort_message_into_hcb(hcb); - put_hcb_at_the_front_of_hardware_queue(hcb); - break; - } - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - return;</programlisting> - - <para>That's all for the ABORT request, although there is one more - issue. Because the ABORT message cleans all the ongoing - transactions on a LUN we have to mark all the other active - transactions on this LUN as aborted. That should be done in the - interrupt routine, after the transaction gets aborted.</para> - - <para>Implementing the CCB abort as a function may be quite a good - idea, this function can be re-used if an I/O transaction times - out. The only difference would be that the timed out transaction - would return the status CAM_CMD_TIMEOUT for the timed out - request. Then the case XPT_ABORT would be small, like - that:</para> - -<programlisting> case XPT_ABORT: - struct ccb *abort_ccb; - abort_ccb = ccb->cab.abort_ccb; - - if(abort_ccb->ccb_h.func_code != XPT_SCSI_IO) { - ccb->ccb_h.status = CAM_UA_ABORT; - xpt_done(ccb); - return; - } - if(xxx_abort_ccb(abort_ccb, CAM_REQ_ABORTED) < 0) - /* no such CCB in our queue */ - ccb->ccb_h.status = CAM_PATH_INVALID; - else - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - return;</programlisting> - </listitem> - - <listitem><para><emphasis>XPT_SET_TRAN_SETTINGS</emphasis> - explicitly - set values of SCSI transfer settings</para> - - <para>The arguments are transferred in the instance "struct ccb_trans_setting cts" -of the union ccb:</para> - - <itemizedlist> - <listitem><para><emphasis>valid</emphasis> - a bitmask showing - which settings should be updated:</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_SYNC_RATE_VALID</emphasis> - - synchronous transfer rate</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_SYNC_OFFSET_VALID</emphasis> - - synchronous offset</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_BUS_WIDTH_VALID</emphasis> - - bus width</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_DISC_VALID</emphasis> - - set enable/disable disconnection</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_TQ_VALID</emphasis> - set - enable/disable tagged queuing</para></listitem> - - <listitem><para><emphasis>flags</emphasis> - consists of two - parts, binary arguments and identification of - sub-operations. The binary arguments are :</para> - <itemizedlist> - <listitem><para><emphasis>CCB_TRANS_DISC_ENB</emphasis> - enable disconnection</para></listitem> - <listitem><para><emphasis>CCB_TRANS_TAG_ENB</emphasis> - - enable tagged queuing</para></listitem> - </itemizedlist> - </listitem> - - <listitem><para>the sub-operations are:</para> - <itemizedlist> - <listitem><para><emphasis>CCB_TRANS_CURRENT_SETTINGS</emphasis> - - change the current negotiations</para></listitem> - - <listitem><para><emphasis>CCB_TRANS_USER_SETTINGS</emphasis> - - remember the desired user values sync_period, sync_offset - - self-explanatory, if sync_offset==0 then the asynchronous mode - is requested bus_width - bus width, in bits (not - bytes)</para></listitem> - </itemizedlist> - </listitem> - - </itemizedlist> - - <para>Two sets of negotiated parameters are supported, the user - settings and the current settings. The user settings are not - really used much in the SIM drivers, this is mostly just a piece - of memory where the upper levels can store (and later recall) - its ideas about the parameters. Setting the user parameters - does not cause re-negotiation of the transfer rates. But when - the SCSI controller does a negotiation it must never set the - values higher than the user parameters, so it's essentially the - top boundary.</para> - - <para>The current settings are, as the name says, - current. Changing them means that the parameters must be - re-negotiated on the next transfer. Again, these "new current - settings" are not supposed to be forced on the device, just they - are used as the initial step of negotiations. Also they must be - limited by actual capabilities of the SCSI controller: for - example, if the SCSI controller has 8-bit bus and the request - asks to set 16-bit wide transfers this parameter must be - silently truncated to 8-bit transfers before sending it to the - device.</para> - - <para>One caveat is that the bus width and synchronous parameters - are per target while the disconnection and tag enabling - parameters are per lun.</para> - - <para>The recommended implementation is to keep 3 sets of - negotiated (bus width and synchronous transfer) - parameters:</para> - - <itemizedlist> - <listitem><para><emphasis>user</emphasis> - the user set, as - above</para></listitem> - - <listitem><para><emphasis>current</emphasis> - those actually - in effect</para></listitem> - - <listitem><para><emphasis>goal</emphasis> - those requested by - setting of the "current" parameters</para></listitem> - </itemizedlist> - - <para>The code looks like:</para> - -<programlisting> struct ccb_trans_settings *cts; - int targ, lun; - int flags; - - cts = &ccb->cts; - targ = ccb_h->target_id; - lun = ccb_h->target_lun; - flags = cts->flags; - if(flags & CCB_TRANS_USER_SETTINGS) { - if(flags & CCB_TRANS_SYNC_RATE_VALID) - softc->user_sync_period[targ] = cts->sync_period; - if(flags & CCB_TRANS_SYNC_OFFSET_VALID) - softc->user_sync_offset[targ] = cts->sync_offset; - if(flags & CCB_TRANS_BUS_WIDTH_VALID) - softc->user_bus_width[targ] = cts->bus_width; - - if(flags & CCB_TRANS_DISC_VALID) { - softc->user_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB; - softc->user_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB; - } - if(flags & CCB_TRANS_TQ_VALID) { - softc->user_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB; - softc->user_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB; - } - } - if(flags & CCB_TRANS_CURRENT_SETTINGS) { - if(flags & CCB_TRANS_SYNC_RATE_VALID) - softc->goal_sync_period[targ] = - max(cts->sync_period, OUR_MIN_SUPPORTED_PERIOD); - if(flags & CCB_TRANS_SYNC_OFFSET_VALID) - softc->goal_sync_offset[targ] = - min(cts->sync_offset, OUR_MAX_SUPPORTED_OFFSET); - if(flags & CCB_TRANS_BUS_WIDTH_VALID) - softc->goal_bus_width[targ] = min(cts->bus_width, OUR_BUS_WIDTH); - - if(flags & CCB_TRANS_DISC_VALID) { - softc->current_tflags[targ][lun] &= ~CCB_TRANS_DISC_ENB; - softc->current_tflags[targ][lun] |= flags & CCB_TRANS_DISC_ENB; - } - if(flags & CCB_TRANS_TQ_VALID) { - softc->current_tflags[targ][lun] &= ~CCB_TRANS_TQ_ENB; - softc->current_tflags[targ][lun] |= flags & CCB_TRANS_TQ_ENB; - } - } - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - return;</programlisting> - - <para>Then when the next I/O request will be processed it will - check if it has to re-negotiate, for example by calling the - function target_negotiated(hcb). It can be implemented like - this:</para> - -<programlisting> int - target_negotiated(struct xxx_hcb *hcb) - { - struct softc *softc = hcb->softc; - int targ = hcb->targ; - - if( softc->current_sync_period[targ] != softc->goal_sync_period[targ] - || softc->current_sync_offset[targ] != softc->goal_sync_offset[targ] - || softc->current_bus_width[targ] != softc->goal_bus_width[targ] ) - return 0; /* FALSE */ - else - return 1; /* TRUE */ - }</programlisting> - - <para>After the values are re-negotiated the resulting values must - be assigned to both current and goal parameters, so for future - I/O transactions the current and goal parameters would be the - same and <function>target_negotiated()</function> would return - TRUE. When the card is initialized (in - <function>xxx_attach()</function>) the current negotiation - values must be initialized to narrow asynchronous mode, the goal - and current values must be initialized to the maximal values - supported by controller.</para></listitem> - - <listitem><para><emphasis>XPT_GET_TRAN_SETTINGS</emphasis> - get values of - SCSI transfer settings</para> - - <para>This operations is the reverse of - XPT_SET_TRAN_SETTINGS. Fill up the CCB instance "struct - ccb_trans_setting cts" with data as requested by the flags - CCB_TRANS_CURRENT_SETTINGS or CCB_TRANS_USER_SETTINGS (if both - are set then the existing drivers return the current - settings). Set all the bits in the valid field.</para></listitem> - - <listitem><para><emphasis>XPT_CALC_GEOMETRY</emphasis> - calculate logical - (BIOS) geometry of the disk</para> - - <para>The arguments are transferred in the instance "struct - ccb_calc_geometry ccg" of the union ccb:</para> - - <itemizedlist> - - <listitem><para><emphasis>block_size</emphasis> - input, block - (A.K.A sector) size in bytes</para></listitem> - - <listitem><para><emphasis>volume_size</emphasis> - input, - volume size in bytes</para></listitem> - - <listitem><para><emphasis>cylinders</emphasis> - output, - logical cylinders</para></listitem> - - <listitem><para><emphasis>heads</emphasis> - output, logical - heads</para></listitem> - - <listitem><para><emphasis>secs_per_track</emphasis> - output, - logical sectors per track</para></listitem> - - </itemizedlist> - - <para>If the returned geometry differs much enough from what the - SCSI controller BIOS thinks and a disk on this SCSI controller - is used as bootable the system may not be able to boot. The - typical calculation example taken from the aic7xxx driver - is:</para> - -<programlisting> struct ccb_calc_geometry *ccg; - u_int32_t size_mb; - u_int32_t secs_per_cylinder; - int extended; - - ccg = &ccb->ccg; - size_mb = ccg->volume_size - / ((1024L * 1024L) / ccg->block_size); - extended = check_cards_EEPROM_for_extended_geometry(softc); - - if (size_mb > 1024 && extended) { - ccg->heads = 255; - ccg->secs_per_track = 63; - } else { - ccg->heads = 64; - ccg->secs_per_track = 32; - } - secs_per_cylinder = ccg->heads * ccg->secs_per_track; - ccg->cylinders = ccg->volume_size / secs_per_cylinder; - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_done(ccb); - return;</programlisting> - - <para>This gives the general idea, the exact calculation depends - on the quirks of the particular BIOS. If BIOS provides no way - set the "extended translation" flag in EEPROM this flag should - normally be assumed equal to 1. Other popular geometries - are:</para> - -<programlisting> 128 heads, 63 sectors - Symbios controllers - 16 heads, 63 sectors - old controllers</programlisting> - - <para>Some system BIOSes and SCSI BIOSes fight with each other - with variable success, for example a combination of Symbios - 875/895 SCSI and Phoenix BIOS can give geometry 128/63 after - power up and 255/63 after a hard reset or soft reboot.</para> - </listitem> - - <listitem><para><emphasis>XPT_PATH_INQ</emphasis> - path inquiry, in other - words get the SIM driver and SCSI controller (also known as HBA - - Host Bus Adapter) properties</para> - - <para>The properties are returned in the instance "struct -ccb_pathinq cpi" of the union ccb:</para> - - <itemizedlist> - - <listitem><para>version_num - the SIM driver version number, now - all drivers use 1</para></listitem> - - <listitem><para>hba_inquiry - bitmask of features supported by - the controller:</para></listitem> - - <listitem><para>PI_MDP_ABLE - supports MDP message (something - from SCSI3?)</para></listitem> - - <listitem><para>PI_WIDE_32 - supports 32 bit wide - SCSI</para></listitem> - - <listitem><para>PI_WIDE_16 - supports 16 bit wide - SCSI</para></listitem> - - <listitem><para>PI_SDTR_ABLE - can negotiate synchronous - transfer rate</para></listitem> - - <listitem><para>PI_LINKED_CDB - supports linked - commands</para></listitem> - - <listitem><para>PI_TAG_ABLE - supports tagged - commands</para></listitem> - - <listitem><para>PI_SOFT_RST - supports soft reset alternative - (hard reset and soft reset are mutually exclusive within a - SCSI bus)</para></listitem> - - <listitem><para>target_sprt - flags for target mode support, 0 - if unsupported</para></listitem> - - <listitem><para>hba_misc - miscellaneous controller - features:</para></listitem> - - <listitem><para>PIM_SCANHILO - bus scans from high ID to low - ID</para></listitem> - - <listitem><para>PIM_NOREMOVE - removable devices not included in - scan</para></listitem> - - <listitem><para>PIM_NOINITIATOR - initiator role not - supported</para></listitem> - - <listitem><para>PIM_NOBUSRESET - user has disabled initial BUS - RESET</para></listitem> - - <listitem><para>hba_eng_cnt - mysterious HBA engine count, - something related to compression, now is always set to - 0</para></listitem> - - <listitem><para>vuhba_flags - vendor-unique flags, unused - now</para></listitem> - - <listitem><para>max_target - maximal supported target ID (7 for - 8-bit bus, 15 for 16-bit bus, 127 for Fibre - Channel)</para></listitem> - - <listitem><para>max_lun - maximal supported LUN ID (7 for older - SCSI controllers, 63 for newer ones)</para></listitem> - - <listitem><para>async_flags - bitmask of installed Async - handler, unused now</para></listitem> - - <listitem><para>hpath_id - highest Path ID in the subsystem, - unused now</para></listitem> - - <listitem><para>unit_number - the controller unit number, - cam_sim_unit(sim)</para></listitem> - - <listitem><para>bus_id - the bus number, - cam_sim_bus(sim)</para></listitem> - - <listitem><para>initiator_id - the SCSI ID of the controller - itself</para></listitem> - - <listitem><para>base_transfer_speed - nominal transfer speed in - KB/s for asynchronous narrow transfers, equals to 3300 for - SCSI</para></listitem> - - <listitem><para>sim_vid - SIM driver's vendor id, a - zero-terminated string of maximal length SIM_IDLEN including - the terminating zero</para></listitem> - - <listitem><para>hba_vid - SCSI controller's vendor id, a - zero-terminated string of maximal length HBA_IDLEN including - the terminating zero</para></listitem> - - <listitem><para>dev_name - device driver name, a zero-terminated - string of maximal length DEV_IDLEN including the terminating - zero, equal to cam_sim_name(sim)</para></listitem> - - </itemizedlist> - - <para>The recommended way of setting the string fields is using - strncpy, like:</para> - -<programlisting> strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);</programlisting> - - <para>After setting the values set the status to CAM_REQ_CMP and mark the -CCB as done.</para> - </listitem> - </itemizedlist> - - </sect1> - - <sect1> - <title>Polling</title> - - <funcSynopsis><funcPrototype> - <funcDef>static void - <function>xxx_poll</function> - </funcDef> - <paramdef> - <parameter>struct cam_sim *sim</parameter> - </paramdef> - </funcPrototype></funcSynopsis> - - <para>The poll function is used to simulate the interrupts when - the interrupt subsystem is not functioning (for example, when - the system has crashed and is creating the system dump). The CAM - subsystem sets the proper interrupt level before calling the - poll routine. So all it needs to do is to call the interrupt - routine (or the other way around, the poll routine may be doing - the real action and the interrupt routine would just call the - poll routine). Why bother about a separate function then ? - Because of different calling conventions. The - <function>xxx_poll</function> routine gets the struct cam_sim - pointer as its argument when the PCI interrupt routine by common - convention gets pointer to the struct - <structName>xxx_softc</structName> and the ISA interrupt routine - gets just the device unit number. So the poll routine would - normally look as:</para> - -<programlisting>static void -xxx_poll(struct cam_sim *sim) -{ - xxx_intr((struct xxx_softc *)cam_sim_softc(sim)); /* for PCI device */ -}</programlisting> - - <para>or</para> - -<programlisting>static void -xxx_poll(struct cam_sim *sim) -{ - xxx_intr(cam_sim_unit(sim)); /* for ISA device */ -}</programlisting> - - </sect1> - - <sect1> - <title>Asynchronous Events</title> - - <para>If an asynchronous event callback has been set up then the - callback function should be defined.</para> - -<programlisting>static void -ahc_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)</programlisting> - - <itemizedlist> - <listitem><para>callback_arg - the value supplied when registering the - callback</para></listitem> - - <listitem><para>code - identifies the type of event</para></listitem> - - <listitem><para>path - identifies the devices to which the event - applies</para></listitem> - - <listitem><para>arg - event-specific argument</para></listitem> - </itemizedlist> - - <para>Implementation for a single type of event, AC_LOST_DEVICE, - looks like:</para> - -<programlisting> struct xxx_softc *softc; - struct cam_sim *sim; - int targ; - struct ccb_trans_settings neg; - - sim = (struct cam_sim *)callback_arg; - softc = (struct xxx_softc *)cam_sim_softc(sim); - switch (code) { - case AC_LOST_DEVICE: - targ = xpt_path_target_id(path); - if(targ <= OUR_MAX_SUPPORTED_TARGET) { - clean_negotiations(softc, targ); - /* send indication to CAM */ - neg.bus_width = 8; - neg.sync_period = neg.sync_offset = 0; - neg.valid = (CCB_TRANS_BUS_WIDTH_VALID - | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID); - xpt_async(AC_TRANSFER_NEG, path, &neg); - } - break; - default: - break; - }</programlisting> - - </sect1> - - <sect1> - <title>Interrupts</title> - - <para>The exact type of the interrupt routine depends on the type - of the peripheral bus (PCI, ISA and so on) to which the SCSI - controller is connected.</para> - - <para>The interrupt routines of the SIM drivers run at the - interrupt level splcam. So <function>splcam()</function> should - be used in the driver to synchronize activity between the - interrupt routine and the rest of the driver (for a - multiprocessor-aware driver things get yet more interesting but - we ignore this case here). The pseudo-code in this document - happily ignores the problems of synchronization. The real code - must not ignore them. A simple-minded approach is to set - <function>splcam()</function> on the entry to the other routines - and reset it on return thus protecting them by one big critical - section. To make sure that the interrupt level will be always - restored a wrapper function can be defined, like:</para> - -<programlisting> static void - xxx_action(struct cam_sim *sim, union ccb *ccb) - { - int s; - s = splcam(); - xxx_action1(sim, ccb); - splx(s); - } - - static void - xxx_action1(struct cam_sim *sim, union ccb *ccb) - { - ... process the request ... - }</programlisting> - - <para>This approach is simple and robust but the problem with it - is that interrupts may get blocked for a relatively long time - and this would negatively affect the system's performance. On - the other hand the functions of the <function>spl()</function> - family have rather high overhead, so vast amount of tiny - critical sections may not be good either.</para> - - <para>The conditions handled by the interrupt routine and the - details depend very much on the hardware. We consider the set of - "typical" conditions.</para> - - <para>First, we check if a SCSI reset was encountered on the bus - (probably caused by another SCSI controller on the same SCSI - bus). If so we drop all the enqueued and disconnected requests, - report the events and re-initialize our SCSI controller. It is - important that during this initialization the controller won't - issue another reset or else two controllers on the same SCSI bus - could ping-pong resets forever. The case of fatal controller - error/hang could be handled in the same place, but it will - probably need also sending RESET signal to the SCSI bus to reset - the status of the connections with the SCSI devices.</para> - -<programlisting> int fatal=0; - struct ccb_trans_settings neg; - struct cam_path *path; - - if( detected_scsi_reset(softc) - || (fatal = detected_fatal_controller_error(softc)) ) { - int targ, lun; - struct xxx_hcb *h, *hh; - - /* drop all enqueued CCBs */ - for(h = softc->first_queued_hcb; h != NULL; h = hh) { - hh = h->next; - free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET); - } - - /* the clean values of negotiations to report */ - neg.bus_width = 8; - neg.sync_period = neg.sync_offset = 0; - neg.valid = (CCB_TRANS_BUS_WIDTH_VALID - | CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID); - - /* drop all disconnected CCBs and clean negotiations */ - for(targ=0; targ <= OUR_MAX_SUPPORTED_TARGET; targ++) { - clean_negotiations(softc, targ); - - /* report the event if possible */ - if(xpt_create_path(&path, /*periph*/NULL, - cam_sim_path(sim), targ, - CAM_LUN_WILDCARD) == CAM_REQ_CMP) { - xpt_async(AC_TRANSFER_NEG, path, &neg); - xpt_free_path(path); - } - - for(lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++) - for(h = softc->first_discon_hcb[targ][lun]; h != NULL; h = hh) { - hh=h->next; - if(fatal) - free_hcb_and_ccb_done(h, h->ccb, CAM_UNREC_HBA_ERROR); - else - free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET); - } - } - - /* report the event */ - xpt_async(AC_BUS_RESET, softc->wpath, NULL); - - /* re-initialization may take a lot of time, in such case - * its completion should be signaled by another interrupt or - * checked on timeout - but for simplicity we assume here that - * it's really fast - */ - if(!fatal) { - reinitialize_controller_without_scsi_reset(softc); - } else { - reinitialize_controller_with_scsi_reset(softc); - } - schedule_next_hcb(softc); - return; - }</programlisting> - - <para>If interrupt is not caused by a controller-wide condition - then probably something has happened to the current hardware - control block. Depending on the hardware there may be other - non-HCB-related events, we just do not consider them here. Then - we analyze what happened to this HCB:</para> - -<programlisting> struct xxx_hcb *hcb, *h, *hh; - int hcb_status, scsi_status; - int ccb_status; - int targ; - int lun_to_freeze; - - hcb = get_current_hcb(softc); - if(hcb == NULL) { - /* either stray interrupt or something went very wrong - * or this is something hardware-dependent - */ - handle as necessary; - return; - } - - targ = hcb->target; - hcb_status = get_status_of_current_hcb(softc);</programlisting> - - <para>First we check if the HCB has completed and if so we check - the returned SCSI status.</para> - -<programlisting> if(hcb_status == COMPLETED) { - scsi_status = get_completion_status(hcb);</programlisting> - - <para>Then look if this status is related to the REQUEST SENSE - command and if so handle it in a simple way.</para> - -<programlisting> if(hcb->flags & DOING_AUTOSENSE) { - if(scsi_status == GOOD) { /* autosense was successful */ - hcb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID; - free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR); - } else { - autosense_failed: - free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_AUTOSENSE_FAIL); - } - schedule_next_hcb(softc); - return; - }</programlisting> - - <para>Else the command itself has completed, pay more attention to - details. If auto-sense is not disabled for this CCB and the - command has failed with sense data then run REQUEST SENSE - command to receive that data.</para> - -<programlisting> hcb->ccb->csio.scsi_status = scsi_status; - calculate_residue(hcb); - - if( (hcb->ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)==0 - && ( scsi_status == CHECK_CONDITION - || scsi_status == COMMAND_TERMINATED) ) { - /* start auto-SENSE */ - hcb->flags |= DOING_AUTOSENSE; - setup_autosense_command_in_hcb(hcb); - restart_current_hcb(softc); - return; - } - if(scsi_status == GOOD) - free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_REQ_CMP); - else - free_hcb_and_ccb_done(hcb, hcb->ccb, CAM_SCSI_STATUS_ERROR); - schedule_next_hcb(softc); - return; - }</programlisting> - - <para>One typical thing would be negotiation events: negotiation - messages received from a SCSI target (in answer to our - negotiation attempt or by target's initiative) or the target is - unable to negotiate (rejects our negotiation messages or does - not answer them).</para> - -<programlisting> switch(hcb_status) { - case TARGET_REJECTED_WIDE_NEG: - /* revert to 8-bit bus */ - softc->current_bus_width[targ] = softc->goal_bus_width[targ] = 8; - /* report the event */ - neg.bus_width = 8; - neg.valid = CCB_TRANS_BUS_WIDTH_VALID; - xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg); - continue_current_hcb(softc); - return; - case TARGET_ANSWERED_WIDE_NEG: - { - int wd; - - wd = get_target_bus_width_request(softc); - if(wd <= softc->goal_bus_width[targ]) { - /* answer is acceptable */ - softc->current_bus_width[targ] = - softc->goal_bus_width[targ] = neg.bus_width = wd; - - /* report the event */ - neg.valid = CCB_TRANS_BUS_WIDTH_VALID; - xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg); - } else { - prepare_reject_message(hcb); - } - } - continue_current_hcb(softc); - return; - case TARGET_REQUESTED_WIDE_NEG: - { - int wd; - - wd = get_target_bus_width_request(softc); - wd = min (wd, OUR_BUS_WIDTH); - wd = min (wd, softc->user_bus_width[targ]); - - if(wd != softc->current_bus_width[targ]) { - /* the bus width has changed */ - softc->current_bus_width[targ] = - softc->goal_bus_width[targ] = neg.bus_width = wd; - - /* report the event */ - neg.valid = CCB_TRANS_BUS_WIDTH_VALID; - xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg); - } - prepare_width_nego_rsponse(hcb, wd); - } - continue_current_hcb(softc); - return; - }</programlisting> - - <para>Then we handle any errors that could have happened during - auto-sense in the same simple-minded way as before. Otherwise we - look closer at the details again.</para> - -<programlisting> if(hcb->flags & DOING_AUTOSENSE) - goto autosense_failed; - - switch(hcb_status) {</programlisting> - - <para>The next event we consider is unexpected disconnect. Which - is considered normal after an ABORT or BUS DEVICE RESET message - and abnormal in other cases.</para> - -<programlisting> case UNEXPECTED_DISCONNECT: - if(requested_abort(hcb)) { - /* abort affects all commands on that target+LUN, so - * mark all disconnected HCBs on that target+LUN as aborted too - */ - for(h = softc->first_discon_hcb[hcb->target][hcb->lun]; - h != NULL; h = hh) { - hh=h->next; - free_hcb_and_ccb_done(h, h->ccb, CAM_REQ_ABORTED); - } - ccb_status = CAM_REQ_ABORTED; - } else if(requested_bus_device_reset(hcb)) { - int lun; - - /* reset affects all commands on that target, so - * mark all disconnected HCBs on that target+LUN as reset - */ - - for(lun=0; lun <= OUR_MAX_SUPPORTED_LUN; lun++) - for(h = softc->first_discon_hcb[hcb->target][lun]; - h != NULL; h = hh) { - hh=h->next; - free_hcb_and_ccb_done(h, h->ccb, CAM_SCSI_BUS_RESET); - } - - /* send event */ - xpt_async(AC_SENT_BDR, hcb->ccb->ccb_h.path_id, NULL); - - /* this was the CAM_RESET_DEV request itself, it's completed */ - ccb_status = CAM_REQ_CMP; - } else { - calculate_residue(hcb); - ccb_status = CAM_UNEXP_BUSFREE; - /* request the further code to freeze the queue */ - hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN; - lun_to_freeze = hcb->lun; - } - break;</programlisting> - - <para>If the target refuses to accept tags we notify CAM about - that and return back all commands for this LUN:</para> - -<programlisting> case TAGS_REJECTED: - /* report the event */ - neg.flags = 0 & ~CCB_TRANS_TAG_ENB; - neg.valid = CCB_TRANS_TQ_VALID; - xpt_async(AC_TRANSFER_NEG, hcb->ccb.ccb_h.path_id, &neg); - - ccb_status = CAM_MSG_REJECT_REC; - /* request the further code to freeze the queue */ - hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN; - lun_to_freeze = hcb->lun; - break;</programlisting> - - <para>Then we check a number of other conditions, with processing - basically limited to setting the CCB status:</para> - -<programlisting> case SELECTION_TIMEOUT: - ccb_status = CAM_SEL_TIMEOUT; - /* request the further code to freeze the queue */ - hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN; - lun_to_freeze = CAM_LUN_WILDCARD; - break; - case PARITY_ERROR: - ccb_status = CAM_UNCOR_PARITY; - break; - case DATA_OVERRUN: - case ODD_WIDE_TRANSFER: - ccb_status = CAM_DATA_RUN_ERR; - break; - default: - /* all other errors are handled in a generic way */ - ccb_status = CAM_REQ_CMP_ERR; - /* request the further code to freeze the queue */ - hcb->ccb->ccb_h.status |= CAM_DEV_QFRZN; - lun_to_freeze = CAM_LUN_WILDCARD; - break; - }</programlisting> - - <para>Then we check if the error was serious enough to freeze the - input queue until it gets proceeded and do so if it is:</para> - -<programlisting> if(hcb->ccb->ccb_h.status & CAM_DEV_QFRZN) { - /* freeze the queue */ - xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); - - /* re-queue all commands for this target/LUN back to CAM */ - - for(h = softc->first_queued_hcb; h != NULL; h = hh) { - hh = h->next; - - if(targ == h->targ - && (lun_to_freeze == CAM_LUN_WILDCARD || lun_to_freeze == h->lun) ) - free_hcb_and_ccb_done(h, h->ccb, CAM_REQUEUE_REQ); - } - } - free_hcb_and_ccb_done(hcb, hcb->ccb, ccb_status); - schedule_next_hcb(softc); - return;</programlisting> - - <para>This concludes the generic interrupt handling although - specific controllers may require some additions.</para> - - </sect1> - - <sect1> - <title>Errors Summary</title> - - <para>When executing an I/O request many things may go wrong. The - reason of error can be reported in the CCB status with great - detail. Examples of use are spread throughout this document. For - completeness here is the summary of recommended responses for - the typical error conditions:</para> - - <itemizedlist> - - <listitem><para><emphasis>CAM_RESRC_UNAVAIL</emphasis> - some - resource is temporarily unavailable and the SIM driver cannot - generate an event when it will become available. An example of - this resource would be some intra-controller hardware resource - for which the controller does not generate an interrupt when - it becomes available.</para></listitem> - - <listitem><para><emphasis>CAM_UNCOR_PARITY</emphasis> - - unrecovered parity error occurred</para></listitem> - - <listitem><para><emphasis>CAM_DATA_RUN_ERR</emphasis> - data - overrun or unexpected data phase (going in other direction - than specified in CAM_DIR_MASK) or odd transfer length for - wide transfer</para></listitem> - - <listitem><para><emphasis>CAM_SEL_TIMEOUT</emphasis> - selection - timeout occurred (target does not respond)</para></listitem> - - <listitem><para><emphasis>CAM_CMD_TIMEOUT</emphasis> - command - timeout occurred (the timeout function ran)</para></listitem> - - <listitem><para><emphasis>CAM_SCSI_STATUS_ERROR</emphasis> - the - device returned error</para></listitem> - - <listitem><para><emphasis>CAM_AUTOSENSE_FAIL</emphasis> - the - device returned error and the REQUEST SENSE COMMAND - failed</para></listitem> - - <listitem><para><emphasis>CAM_MSG_REJECT_REC</emphasis> - MESSAGE - REJECT message was received</para></listitem> - - <listitem><para><emphasis>CAM_SCSI_BUS_RESET</emphasis> - received - SCSI bus reset</para></listitem> - - <listitem><para><emphasis>CAM_REQ_CMP_ERR</emphasis> - - "impossible" SCSI phase occurred or something else as weird or - just a generic error if further detail is not - available</para></listitem> - - <listitem><para><emphasis>CAM_UNEXP_BUSFREE</emphasis> - - unexpected disconnect occurred</para></listitem> - - <listitem><para><emphasis>CAM_BDR_SENT</emphasis> - BUS DEVICE - RESET message was sent to the target</para></listitem> - - <listitem><para><emphasis>CAM_UNREC_HBA_ERROR</emphasis> - - unrecoverable Host Bus Adapter Error</para></listitem> - - <listitem><para><emphasis>CAM_REQ_TOO_BIG</emphasis> - the request - was too large for this controller</para></listitem> - - <listitem><para><emphasis>CAM_REQUEUE_REQ</emphasis> - this - request should be re-queued to preserve transaction ordering. - This typically occurs when the SIM recognizes an error that - should freeze the queue and must place other queued requests - for the target at the sim level back into the XPT - queue. Typical cases of such errors are selection timeouts, - command timeouts and other like conditions. In such cases the - troublesome command returns the status indicating the error, - the and the other commands which have not be sent to the bus - yet get re-queued.</para></listitem> - - <listitem><para><emphasis>CAM_LUN_INVALID</emphasis> - the LUN - ID in the request is not supported by the SCSI - controller</para></listitem> - - <listitem><para><emphasis>CAM_TID_INVALID</emphasis> - the - target ID in the request is not supported by the SCSI - controller</para></listitem> - </itemizedlist> - </sect1> - - <sect1> - <title>Timeout Handling</title> - - <para>When the timeout for an HCB expires that request should be - aborted, just like with an XPT_ABORT request. The only - difference is that the returned status of aborted request should - be CAM_CMD_TIMEOUT instead of CAM_REQ_ABORTED (that's why - implementation of the abort better be done as a function). But - there is one more possible problem: what if the abort request - itself will get stuck? In this case the SCSI bus should be - reset, just like with an XPT_RESET_BUS request (and the idea - about implementing it as a function called from both places - applies here too). Also we should reset the whole SCSI bus if a - device reset request got stuck. So after all the timeout - function would look like:</para> - -<programlisting>static void -xxx_timeout(void *arg) -{ - struct xxx_hcb *hcb = (struct xxx_hcb *)arg; - struct xxx_softc *softc; - struct ccb_hdr *ccb_h; - - softc = hcb->softc; - ccb_h = &hcb->ccb->ccb_h; - - if(hcb->flags & HCB_BEING_ABORTED - || ccb_h->func_code == XPT_RESET_DEV) { - xxx_reset_bus(softc); - } else { - xxx_abort_ccb(hcb->ccb, CAM_CMD_TIMEOUT); - } -}</programlisting> - - <para>When we abort a request all the other disconnected requests - to the same target/LUN get aborted too. So there appears a - question, should we return them with status CAM_REQ_ABORTED or - CAM_CMD_TIMEOUT ? The current drivers use CAM_CMD_TIMEOUT. This - seems logical because if one request got timed out then probably - something really bad is happening to the device, so if they - would not be disturbed they would time out by themselves.</para> - - </sect1> - -</chapter> diff --git a/en_US.ISO8859-1/books/arch-handbook/sysinit/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/sysinit/chapter.sgml deleted file mode 100644 index 468e739d12..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/sysinit/chapter.sgml +++ /dev/null @@ -1,161 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: $ ---> - -<chapter id="sysinit"> - <title>The Sysinit Framework</title> - - <para>Sysinit is the framework for a generic call sort and dispatch - mechanisim. FreeBSD currently uses it for the dynamic - initialization of the kernel. Sysinit allows FreeBSD's kernel - subsystems to be reordered, and added, removed, and replaced at - kernel link time when the kernel or one of its modules is loaded - without having to edit a staticly ordered initilization routing - and recompile the kernel. This system also allows kernel modules, - currently called <firstterm>KLD's</firstterm>, to be seperatly - compiled, linked, and initilized at boot time and loaded even - later while the system is already running. This is accomplished - using the <quote>kernel linker</quote> and <quote>linker - sets</quote>.</para> - - <sect1> - <title>Terminology</title> - - <variablelist> - <varlistentry> - <term>Linker Set</term> - <listitem> - <para>A linker technique in which the linker gathers - staticly declared data throughout a program's source files - into a single contagiously addressable unit of - data.</para> - </listitem> - </varlistentry> - </variablelist> - </sect1> - - <sect1> - <title>Sysinit Operation</title> - - <para>Sysinit relies on the ability of the linker to take static - data declared at multiple locations throughout a program's - source and group it together as a single contagious chunk of - data. This linker technique is called a <quote>linker - set</quote>. Sysinit uses two linker sets to maintain two data - sets containing each consumer's call order, function, and a - pointer to the data to pass to taht function.</para> - - <para>Sysinit uses two priorites when ordering the functions for - execution. The first priority is a subsystem ID giving an - overall order Sysinit's dispatch of funtions. Current predeclard - ID's are in <filename><sys/kernel.h></filename> in the enum - list <literal>sysinit_sub_id</literal>. The second priority used - is an element order within the subsystem. Current predeclard - subsystem element orders are in - <filename><sys/kernel.h></filename> in the enum list - <literal>sysinit_elem_order</literal>.</para> - - <para>There are currently two uses for Sysinit. Function dispatch - at system startup and kernel module loads, and function dispatch - at system shutdown and kernel module unload.</para> - </sect1> - - - <sect1> - <title>Using Sysinit</title> - - <sect2> - <title>Interface</title> - - <sect3> - <title>Headers</title> - - <programlisting><sys/kernel.h></programlisting> - </sect3> - - <sect3> - <title>Macros</title> - - <programlisting>SYSINIT(uniquifier, subsystem, order, func, ident) - SYSUNINIT(uniquifier, subsystem, order, func, ident)</programlisting> - </sect3> - </sect2> - - <sect2> - <title>Startup</title> - - <para>The <literal>SYSINIT()</literal> macro creates the - necessary sysinit data in Sysinit's startup data set for - Sysinit to sort and dispatch a function at system startup and - module load. <literal>SYSINIT()</literal> takes a uniquifier - that Sysinit uses identify the particular function dispatch - data, the subsystem order, the subsystem element order, the - function to call, and the data to pass the fuction. All - functions must take a constant pointer argument. - </para> - - <para>For example:</para> - - <programlisting>#include <sys/kernel.h> - -void foo_null(void *unused) -{ - foo_doo(); -} -SYSINIT(foo_null, SI_SUB_FOO, SI_ORDER_FOO, NULL); - -struct foo foo_voodoo = { - FOO_VOODOO; -} - -void foo_arg(void *vdata) -{ - struct foo *foo = (struct foo *)vdata; - foo_data(foo); -} -SYSINIT(foo_arg, SI_SUB_FOO, SI_ORDER_FOO, foo_voodoo); - </programlisting> - </sect2> - - <sect2> - <title>Shutdown</title> - - <para>The <literal>SYSUNINIT()</literal> macro behaves similarly - to the <literal>SYSINIT()</literal> macro except that it adds - the Sysinit data to Sysinit's shutdown data set.</para> - - <para>For example:</para> - - <programlisting>#include <sys/kernel.h> - -void foo_cleanup(void *unused) -{ - foo_kill(); -} -SYSUNINIT(foo_cleanup, SI_SUB_FOO, SI_ORDER_FOO, NULL); - -struct foo_stack foo_stack = { - FOO_STACK_VOODOO; -} - -void foo_flush(void *vdata) -{ -} -SYSUNINIT(foo_flush, SI_SUB_FOO, SI_ORDER_FOO, foo_stack); - </programlisting> - </sect2> - </sect1> -</chapter> - -<!-- - Local Variables: - mode: sgml - sgml-declaration: "../chapter.decl" - sgml-indent-data: t - sgml-omittag: nil - sgml-always-quote-attributes: t - sgml-parent-document: ("../book.sgml" "part" "chapter") - End: ---> diff --git a/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml deleted file mode 100644 index 9656256e31..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/usb/chapter.sgml +++ /dev/null @@ -1,623 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> - -<chapter id="usb"> - <title>USB Devices</title> - - <para><emphasis>This chapter was written by &a.nhibma;. Modifications made for - the handbook by &a.murray;.</emphasis></para> - - <sect1> - <title>Introduction</title> - - <para>The Universal Serial Bus (USB) is a new way of attaching - devices to personal computers. The bus architecture features - two-way communication and has been developed as a response to - devices becoming smarter and requiring more interaction with the - host. USB support is included in all current PC chipsets and is - therefore available in all recently built PCs. Apple's - introduction of the USB-only iMac has been a major incentive for - hardware manufacturers to produce USB versions of their devices. - The future PC specifications specify that all legacy connectors - on PCs should be replaced by one or more USB connectors, - providing generic plug and play capabilities. Support for USB - hardware was available at a very early stage in NetBSD and was - developed by Lennart Augustsson for the NetBSD project. The - code has been ported to FreeBSD and we are currently maintaining - a shared code base. For the implementation of the USB subsystem - a number of features of USB are important.</para> - - <para><emphasis>Lennart Augustsson has done most of the implementation of - the USB support for the NetBSD project. Many thanks for this - incredible amount of work. Many thanks also to Ardy and Dirk for - their comments and proofreading of this paper.</emphasis></para> - - <itemizedlist> - - <listitem><para>Devices connect to ports on the computer - directly or on devices called hubs, forming a treelike device - structure.</para></listitem> - - <listitem><para>The devices can be connected and disconnected at - run time.</para></listitem> - - <listitem><para>Devices can suspend themselves and trigger - resumes of the host system</para></listitem> - - <listitem><para>As the devices can be powered from the bus, the - host software has to keep track of power budgets for each - hub.</para></listitem> - - <listitem><para>Different quality of service requirements by the - different device types together with the maximum of 126 - devices that can be connected to the same bus, require proper - scheduling of transfers on the shared bus to take full - advantage of the 12Mbps bandwidth available. (over 400Mbps - with USB 2.0)</para></listitem> - - <listitem><para>Devices are intelligent and contain easily - accessible information about themselves</para></listitem> - - </itemizedlist> - - <para>The development of drivers for the USB subsystem and devices - connected to it is supported by the specifications that have - been developed and will be developed. These specifications are - publicly available from the USB home pages. Apple has been very - strong in pushing for standards based drivers, by making drivers - for the generic classes available in their operating system - MacOS and discouraging the use of separate drivers for each new - device. This chapter tries to collate essential information for a - basic understanding of the present implementation of the USB - stack in FreeBSD/NetBSD. It is recommended however to read it - together with the relevant specifications mentioned in the - references below.</para> - - <sect2> - <title>Structure of the USB Stack</title> - - <para>The USB support in FreeBSD can be split into three - layers. The lowest layer contains the host controller driver, - providing a generic interface to the hardware and its scheduling - facilities. It supports initialisation of the hardware, - scheduling of transfers and handling of completed and/or failed - transfers. Each host controller driver implements a virtual hub - providing hardware independent access to the registers - controlling the root ports on the back of the machine.</para> - - <para>The middle layer handles the device connection and - disconnection, basic initialisation of the device, driver - selection, the communication channels (pipes) and does - resource management. This services layer also controls the - default pipes and the device requests transferred over - them.</para> - - <para>The top layer contains the individual drivers supporting - specific (classes of) devices. These drivers implement the - protocol that is used over the pipes other than the default - pipe. They also implement additional functionality to make the - device available to other parts of the kernel oruserland. They - use the USB driver interface (USBDI) exposed by the services - layer.</para> - </sect2> - </sect1> - - <sect1 id="usb-hc"> - <title>Host Controllers</title> - - <para>The host controller (HC) controls the transmission of - packets on the bus. Frames of 1 millisecond are used. At the - start of each frame the host controller generates a Start of - Frame (SOF) packet.</para> - - <para>The SOF packet is used to synchronise to the start of the - frame and to keep track of the frame number. Within each frame - packets are transferred, either from host to device (out) or - from device to host (in). Transfers are always initiated by the - host (polled transfers). Therefore there can only be one host - per USB bus. Each transfer of a packet has a status stage in - which the recipient of the data can return either ACK - (acknowledge reception), NAK (retry), STALL (error condition) or - nothing (garbled data stage, device not available or - disconnected). Section 8.5 of the <ulink - url="http://www.usb.org/developers/docs.html">USB - specification</ulink> explains the details of packets in more - detail. Four different types of transfers can occur on a USB - bus: control, bulk, interrupt and isochronous. The types of - transfers and their characteristics are described below (`Pipes' - subsection).</para> - - <para>Large transfers between the device on the USB bus and the - device driver are split up into multiple packets by the host - controller or the HC driver.</para> - - <para>Device requests (control transfers) to the default endpoints - are special. They consist of two or three phases: SETUP, DATA - (optional) and STATUS. The set-up packet is sent to the - device. If there is a data phase, the direction of the data - packet(s) is given in the set-up packet. The direction in the - status phase is the opposite of the direction during the data - phase, or IN if there was no data phase. The host controller - hardware also provides registers with the current status of the - root ports and the changes that have occurred since the last - reset of the status change register. Access to these registers - is provided through a virtualised hub as suggested in the USB - specification [ 2]. Thevirtual hub must comply with the hub - device class given in chapter 11 of that specification. It must - provide a default pipe through which device requests can be sent - to it. It returns the standard andhub class specific set of - descriptors. It should also provide an interrupt pipe that - reports changes happening at its ports. There are currently two - specifications for host controllers available: <ulink - url="http://developer.intel.com/design/USB/UHCI11D.htm">Universal - Host Controller Interface</ulink> (UHCI; Intel) and <ulink - url="http://www.compaq.com/productinfo/development/openhci.html">Open - Host Controller Interface</ulink> (OHCI; Compaq, Microsoft, - National Semiconductor). The UHCI specification has been - designed to reduce hardware complexity byrequiring the host - controller driver to supply a complete schedule of the transfers - for each frame. OHCI type controllers are much more independent - by providing a more abstract interface doing alot of work - themselves. </para> - - <sect2> - <title>UHCI</title> - - <para>The UHCI host controller maintains a framelist with 1024 - pointers to per frame data structures. It understands two - different data types: transfer descriptors (TD) and queue - heads (QH). Each TD represents a packet to be communicated to - or from a device endpoint. QHs are a means to groupTDs (and - QHs) together.</para> - - <para>Each transfer consists of one or more packets. The UHCI - driver splits large transfers into multiple packets. For every - transfer, apart from isochronous transfers, a QH is - allocated. For every type of transfer these QHs are collected - at a QH for that type. Isochronous transfers have to be - executed first because of the fixed latency requirement and - are directly referred to by the pointer in the framelist. The - last isochronous TD refers to the QH for interrupt transfers - for that frame. All QHs for interrupt transfers point at the - QH for control transfers, which in turn points at the QH for - bulk transfers. The following diagram gives a graphical - overview of this:</para> - - <para>This results in the following schedule being run in each - frame. After fetching the pointer for the current frame from - the framelist the controller first executes the TDs for all - the isochronous packets in that frame. The last of these TDs - refers to the QH for the interrupt transfers for - thatframe. The host controller will then descend from that QH - to the QHs for the individual interrupt transfers. After - finishing that queue, the QH for the interrupt transfers will - refer the controller to the QH for all control transfers. It - will execute all the subqueues scheduled there, followed by - all the transfers queued at the bulk QH. To facilitate the - handling of finished or failed transfers different types of - interrupts are generatedby the hardware at the end of each - frame. In the last TD for a transfer the Interrupt-On - Completion bit is set by the HC driver to flag an interrupt - when the transfer has completed. An error interrupt is flagged - if a TD reaches its maximum error count. If the short packet - detect bit is set in a TD and less than the set packet length - is transferred this interrupt is flagged to notify - the controller driver of the completed transfer. It is the host - controller driver's task to find out which transfer has - completed or produced an error. When called the interrupt - service routine will locate all the finished transfers and - call their callbacks.</para> - - <para>See for a more elaborate description the <ulink - url="http://developer.intel.com/design/USB/UHCI11D.htm">UHCI - specification.</ulink></para> - - </sect2> - - <sect2> - <title>OHCI</title> - - <para>Programming an OHCI host controller is much simpler. The - controller assumes that a set of endpoints is available, and - is aware of scheduling priorities and the ordering of the - types of transfers in a frame. The main data structure used by - the host controller is the endpoint descriptor (ED) to which - aqueue of transfer descriptors (TDs) is attached. The ED - contains the maximum packet size allowed for an endpoint and - the controller hardware does the splitting into packets. The - pointers to the data buffers are updated after each transfer - and when the start and end pointer are equal, the TD is - retired to the done-queue. The four types of endpoints have - their own queues. Control and bulk endpoints are queued each at - their own queue. Interrupt EDs are queued in a tree, with the - level in the tree defining the frequency at which they - run.</para> - - <para>framelist interruptisochronous control bulk</para> - - <para>The schedule being run by the host controller in each - frame looks as follows. The controller will first run the - non-periodic control and bulk queues, up to a time limit set - by the HC driver. Then the interrupt transfers for that frame - number are run, by using the lower five bits of the frame - number as an index into level 0 of the tree of interrupts - EDs. At the end of this tree the isochronous EDs are connected - and these are traversed subsequently. The isochronous TDs - contain the frame number of the first frame the transfer - should be run in. After all the periodic transfers have been - run, the control and bulk queues are traversed - again. Periodically the interrupt service routine is called to - process the done queue and call the callbacks for each - transfer and reschedule interrupt and isochronous - endpoints.</para> - - <para>See for a more elaborate description the <ulink - url="http://www.compaq.com/productinfo/development/openhci.html"> - OHCI specification</ulink>. Services layer The middle layer - provides access to the device in a controlled way and - maintains resources inuse by the different drivers and the - services layer. The layer takes care of the following - aspects:</para> - - <itemizedlist> - <listitem><para>The device configuration - information</para></listitem> - <listitem><para>The pipes to communicate with a - device</para></listitem> - <listitem><para>Probing and attaching and detaching form a - device.</para></listitem> - </itemizedlist> - - </sect2> - </sect1> - - <sect1 id="usb-dev"> - <title>USB Device Information</title> - - <sect2> - <title>Device configuration information</title> - - <para>Each device provides different levels of configuration - information. Each device has one or more configurations, of - which one is selected during probe/attach. A configuration - provides power and bandwidth requirements. Within each - configuration there can be multiple interfaces. A device - interface is a collection of endpoints. For example USB - speakers can have an interface for the audio data (Audio - Class) and an interface for the knobs, dials and buttons (HID - Class). All interfaces in a configuration areactive at the - same time and can be attached to by different drivers. Each - interface can have alternates, providing different quality of - service parameters. In for example cameras this is used to - provide different frame sizes and numbers of frames per - second.</para> - - <para>Within each interface 0 or more endpoints can be - specified. Endpoints are the unidirectional access points for - communicating with a device. They provide buffers to - temporarily store incoming or outgoing data from the - device. Each endpoint has a unique address within - a configuration, the endpoint's number plus its direction. The - default endpoint, endpoint 0, is not part of any interface and - available in all configurations. It is managed by the services - layer and not directly available to device drivers.</para> - - <para>Level 0 Level 1 Level 2 Slot 0</para> - <para>Slot 3 Slot 2 Slot 1</para> - <para>(Only 4 out of 32 slots shown)</para> - - <para>This hierarchical configuration information is described - in the device by a standard set of descriptors (see section 9.6 - of the USB specification [ 2]). They can be requested through - the Get Descriptor Request. The services layer caches these - descriptors to avoid unnecessary transferson the USB - bus. Access to the descriptors is provided through function - calls.</para> - - <itemizedlist> - <listitem><para>Device descriptors: General information about - the device, like Vendor, Product and Revision Id, supported - device class, subclass and protocol if applicable, maximum - packet size for the default endpoint, etc.</para></listitem> - - <listitem><para>Configuration descriptors: The number of - interfaces in this configuration, suspend and resume - functionality supported and power - requirements.</para></listitem> - - <listitem><para>Interface descriptors: interface class, - subclass and protocol if applicable, number of alternate - settings for the interface and the number of - endpoints.</para></listitem> - - <listitem><para>Endpoint descriptors: Endpoint address, - direction and type, maximum packet size supported and - polling frequency if type is interrupt endpoint. There is no - descriptor for thedefault endpoint (endpoint 0) and it is - never counted in an interface descriptor.</para></listitem> - - <listitem><para>String descriptors: In the other descriptors - string indices are supplied for some fields.These can be - used to retrieve descriptive strings, possibly in multiple - languages.</para></listitem> - - </itemizedlist> - - <para>Class specifications can add their own descriptor types - that are available through the GetDescriptor Request.</para> - - <para>Pipes Communication to end points on a device flows - through so-called pipes. Drivers submit transfers to endpoints - to a pipe and provide a callback to be called on completion or - failure of the transfer (asynchronous transfers) or wait for - completion (synchronous transfer). Transfers to an endpoint - are serialised in the pipe. A transfer can either complete, - fail or time-out (if a time-out has been set). There are two - types of time-outs for transfers. Time-outs can happen due to - time-out on the USBbus (milliseconds). These time-outs are - seen as failures and can be due to disconnection of the - device. A second form of time-out is implemented in software - and is triggered when a transfer does not complete within a - specified amount of time (seconds). These are caused by a - device acknowledging negatively (NAK) the transferred - packets. The cause for this is the device not being ready to - receive data, buffer under- or overrun or protocol - errors.</para> - - <para>If a transfer over a pipe is larger than the maximum - packet size specified in the associated endpoint descriptor, - the host controller (OHCI) or the HC driver (UHCI) will split - the transfer into packets of maximum packet size, with the - last packet possibly smaller than the maximum - packetsize.</para> - - <para>Sometimes it is not a problem for a device to return less - data than requested. For example abulk-in-transfer to a modem - might request 200 bytes of data, but the modem has only 5 - bytes available at that time. The driver can set the short - packet (SPD) flag. It allows the host controller to accept a - packet even if the amount of data transferred is less than - requested. This flag is only valid for in-transfers, as the - amount of data to be sent to a device is always known - beforehand. If an unrecoverable error occurs in a device - during a transfer the pipe is stalled. Before any more data is - accepted or sent the driver needs to resolve the cause of the - stall and clear the endpoint stall condition through send the - clear endpoint halt device request over the default - pipe. The default endpoint should never stall.</para> - - <para>There are four different types of endpoints and - corresponding pipes: - Control pipe / default pipe: There is - one control pipe per device, connected to the default endpoint - (endpoint 0). The pipe carries the device requests and - associated data. The difference between transfers over the - default pipe and other pipes is that the protocol for - thetransfers is described in the USB specification [ 2]. These - requests are used to reset and configure the device. A basic - set of commands that must be supported by each device is - provided in chapter 9 of the USB specification [ 2]. The - commands supported on this pipe canbe extended by a device - class specification to support additional - functionality.</para> - - <itemizedlist> - <listitem><para>Bulk pipe: This is the USB equivalent to a raw - transmission medium.</para></listitem> - <listitem><para>Interrupt pipe: The host sends a request for - data to the device and if the device has nothing to send, it - will NAK the data packet. Interrupt transfers are scheduled - at a frequency specifiedwhen creating the - pipe.</para></listitem> - - <listitem><para>Isochronous pipe: These pipes are intended for - isochronous data, for example video oraudio streams, with - fixed latency, but no guaranteed delivery. Some support for - pipes of this type is available in the current - implementation. Packets in control, bulk and interrupt - transfers are retried if an error occurs during transmission - or the device acknowledges the packet negatively (NAK) due to - for example lack of buffer space to store the incoming - data. Isochronous packets are however not retried in case of - failed delivery or NAK of a packet as this might violate the - timing constraints.</para></listitem> - </itemizedlist> - - <para>The availability of the necessary bandwidth is calculated - during the creation of the pipe. Transfersare scheduled within - frames of 1 millisecond. The bandwidth allocation within a - frame is prescribed by the USB specification, section 5.6 [ - 2]. Isochronous and interrupt transfers areallowed to consume - up to 90% of the bandwidth within a frame. Packets for control - and bulk transfers are scheduled after all isochronous and - interrupt packets and will consume all the remaining - bandwidth.</para> - - <para>More information on scheduling of transfers and bandwidth - reclamation can be found in chapter 5of the USB specification - [ 2], section 1.3 of the UHCI specification [ 3] and section - 3.4.2 of the OHCI specification [4].</para> - - </sect2> - </sect1> - - <sect1 id="usb-devprobe"> - <title>Device probe and attach</title> - - <para>After the notification by the hub that a new device has been - connected, the service layer switcheson the port, providing the - device with 100 mA of current. At this point the device is in - its default state and listening to device address 0. The - services layer will proceed to retrieve the various descriptors - through the default pipe. After that it will send a Set Address - request to move the device away from the default device address - (address 0). Multiple device drivers might be able to support - the device. For example a modem driver might beable to support - an ISDN TA through the AT compatibility interface. A driver for - that specific model of the ISDN adapter might however be able to - provide much better support for this device. To support this - flexibility, the probes return priorities indicating their level - of support. Support for a specific revision of a product ranks - the highest and the generic driver the lowest priority. It might - also be that multiple drivers could attach to one device if - there are multiple interfaceswithin one configuration. Each - driver only needs to support a subset of the interfaces.</para> - - <para>The probing for a driver for a newly attached device checks - first for device specific drivers. If notfound, the probe code - iterates over all supported configurations until a driver - attaches in a configuration. To support devices with multiple - drivers on different interfaces, the probe iteratesover all - interfaces in a configuration that have not yet been claimed by - a driver. Configurations that exceed the power budget for the - hub are ignored. During attach the driver should initialise the - device to its proper state, but not reset it, as this will make - the device disconnect itself from the bus and restart the - probing process for it. To avoid consuming unnecessary bandwidth - should not claim the interrupt pipe at attach time, but - should postpone allocating the pipe until the file is opened and - the data is actually used. When the file is closed the pipe - should be closed again, eventhough the device might still be - attached.</para> - - <sect2> - <title>Device disconnect and detach</title> - - <para>A device driver should expect to receive errors during any - transaction with the device. The designof USB supports and - encourages the disconnection of devices at any point in - time. Drivers should make sure that they do the right thing - when the device disappears.</para> - - <para>Furthermore a device that has been disconnected and - reconnected will not be reattached at the same device - instance. This might change in the future when more devices - support serial numbers (see the device descriptor) or other - means of defining an identity for a device have been - developed.</para> - - <para>The disconnection of a device is signalled by a hub in the - interrupt packet delivered to the hub driver. The status - change information indicates which port has seen a connection - change. The device detach method for all device drivers for - the device connected on that port are called and the structures - cleaned up. If the port status indicates that in the mean time - a device has been connected to that port, the procedure for - probing and attaching the device will be started. A device - reset will produce a disconnect-connect sequence on the hub - and will be handled as described above.</para> - - </sect2> - </sect1> - - <sect1 id="usb-protocol"> - <title>USB Drivers Protocol Information</title> - - <para>The protocol used over pipes other than the default pipe is - undefined by the USB specification. Information on this can be - found from various sources. The most accurate source is the - developer's section on the USB home pages [ 1]. From these pages - a growing number of deviceclass specifications are - available. These specifications specify what a compliant device - should look like from a driver perspective, basic functionality - it needs to provide and the protocol that is to be used over the - communication channels. The USB specification [ 2] includes the - description of the Hub Class. A class specification for Human - Interface Devices (HID) has been created to cater for keyboards, - tablets, bar-code readers, buttons, knobs, switches, etc. A - third example is the class specification for mass storage - devices. For a full list of device classes see the developers - sectionon the USB home pages [ 1].</para> - - <para>For many devices the protocol information has not yet been - published however. Information on the protocol being used might - be available from the company making the device. Some companies - will require you to sign a Non -Disclosure Agreement (NDA) - before giving you the specifications. This in most cases - precludes making the driver open source.</para> - - <para>Another good source of information is the Linux driver - sources, as a number of companies have started to provide drivers - for Linux for their devices. It is always a good idea to contact - the authors of those drivers for their source of - information.</para> - - <para>Example: Human Interface Devices The specification for the - Human Interface Devices like keyboards, mice, tablets, buttons, - dials,etc. is referred to in other device class specifications - and is used in many devices.</para> - - <para>For example audio speakers provide endpoints to the digital - to analogue converters and possibly an extra pipe for a - microphone. They also provide a HID endpoint in a separate - interface for the buttons and dials on the front of the - device. The same is true for the monitor control class. It is - straightforward to build support for these interfaces through - the available kernel and userland libraries together with the - HID class driver or the generic driver. Another device that - serves as an example for interfaces within one configuration - driven by different device drivers is a cheap keyboard with - built-in legacy mouse port. To avoid having the cost of - including the hardware for a USB hub in the device, - manufacturers combined the mouse data received from the PS/2 port - on the back of the keyboard and the keypresses from the keyboard - into two separate interfaces in the same configuration. The - mouse and keyboard drivers each attach to the appropriate - interface and allocate the pipes to the two independent - endpoints.</para> - - <para>Example: Firmware download Many devices that have been - developed are based on a general purpose processor with - anadditional USB core added to it. Because the development of - drivers and firmware for USB devices is still very new, many - devices require the downloading of the firmware after they - have been connected.</para> - - <para>The procedure followed is straightforward. The device - identifies itself through a vendor and product Id. The first - driver probes and attaches to it and downloads the firmware into - it. After that the device soft resets itself and the driver is - detached. After a short pause the devicere announces its presence - on the bus. The device will have changed its - vendor/product/revision Id to reflect the fact that it has been - supplied with firmware and as a consequence a second driver will - probe it and attach to it.</para> - - <para>An example of these types of devices is the ActiveWire I/O - board, based on the EZ-USB chip. For this chip a generic firmware - downloader is available. The firmware downloaded into the - ActiveWire board changes the revision Id. It will then perform a - soft reset of the USB part of the EZ-USB chip to disconnect from - the USB bus and again reconnect.</para> - - <para>Example: Mass Storage Devices Support for mass storage - devices is mainly built around existing protocols. The Iomega - USB Zipdrive is based on the SCSI version of their drive. The - SCSI commands and status messages are wrapped in blocks and - transferred over the bulk pipes to and from the device, - emulating a SCSI controller over the USB wire. ATAPI and UFI - commands are supported in a similar fashion.</para> - - <para>The Mass Storage Specification supports 2 different types of - wrapping of the command block.The initial attempt was based on - sending the command and status through the default pipe and - using bulk transfers for the data to be moved between the host - and the device. Based on experience a second approach was - designed that was based on wrapping the command and status - blocks and sending them over the bulk out and in endpoint. The - specification specifies exactly what has to happen when and what - has to be done in case an error condition is encountered. The - biggest challenge when writing drivers for these devices is to - fit USB based protocol into theexisting support for mass storage - devices. CAM provides hooks to do this in a fairly straight - forward way. ATAPI is less simple as historically the IDE - interface has never had many different appearances.</para> - - <para>The support for the USB floppy from Y-E Data is again less - straightforward as a new command set has been designed.</para> - - </sect1> - -</chapter>
\ No newline at end of file diff --git a/en_US.ISO8859-1/books/arch-handbook/vm/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/vm/chapter.sgml deleted file mode 100644 index 4710973d5f..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/vm/chapter.sgml +++ /dev/null @@ -1,255 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO_8859-1/books/developers-handbook/usb/chapter.sgml,v 1.1 2001/04/13 09:05:13 murray Exp $ ---> - -<chapter id="vm"> - <title>Virtual Memory System</title> - - <sect1 id="internals-vm"> - <title>The FreeBSD VM System</title> - - <para><emphasis>Contributed by &a.dillon;. 6 Feb 1999</emphasis></para> - - <sect2> - <title>Management of physical - memory—<literal>vm_page_t</literal></title> - - <para>Physical memory is managed on a page-by-page basis through the - <literal>vm_page_t</literal> structure. Pages of physical memory are - categorized through the placement of their respective - <literal>vm_page_t</literal> structures on one of several paging - queues.</para> - - <para>A page can be in a wired, active, inactive, cache, or free state. - Except for the wired state, the page is typically placed in a doubly - link list queue representing the state that it is in. Wired pages - are not placed on any queue.</para> - - <para>FreeBSD implements a more involved paging queue for cached and - free pages in order to implement page coloring. Each of these states - involves multiple queues arranged according to the size of the - processor's L1 and L2 caches. When a new page needs to be allocated, - FreeBSD attempts to obtain one that is reasonably well aligned from - the point of view of the L1 and L2 caches relative to the VM object - the page is being allocated for.</para> - - <para>Additionally, a page may be held with a reference count or locked - with a busy count. The VM system also implements an <quote>ultimate - locked</quote> state for a page using the PG_BUSY bit in the page's - flags.</para> - - <para>In general terms, each of the paging queues operates in a LRU - fashion. A page is typically placed in a wired or active state - initially. When wired, the page is usually associated with a page - table somewhere. The VM system ages the page by scanning pages in a - more active paging queue (LRU) in order to move them to a less-active - paging queue. Pages that get moved into the cache are still - associated with a VM object but are candidates for immediate reuse. - Pages in the free queue are truly free. FreeBSD attempts to minimize - the number of pages in the free queue, but a certain minimum number of - truly free pages must be maintained in order to accommodate page - allocation at interrupt time.</para> - - <para>If a process attempts to access a page that does not exist in its - page table but does exist in one of the paging queues ( such as the - inactive or cache queues), a relatively inexpensive page reactivation - fault occurs which causes the page to be reactivated. If the page - does not exist in system memory at all, the process must block while - the page is brought in from disk.</para> - - <para>FreeBSD dynamically tunes its paging queues and attempts to - maintain reasonable ratios of pages in the various queues as well as - attempts to maintain a reasonable breakdown of clean v.s. dirty pages. - The amount of rebalancing that occurs depends on the system's memory - load. This rebalancing is implemented by the pageout daemon and - involves laundering dirty pages (syncing them with their backing - store), noticing when pages are activity referenced (resetting their - position in the LRU queues or moving them between queues), migrating - pages between queues when the queues are out of balance, and so forth. - FreeBSD's VM system is willing to take a reasonable number of - reactivation page faults to determine how active or how idle a page - actually is. This leads to better decisions being made as to when to - launder or swap-out a page.</para> - </sect2> - - <sect2> - <title>The unified buffer - cache—<literal>vm_object_t</literal></title> - - <para>FreeBSD implements the idea of a generic <quote>VM object</quote>. - VM objects can be associated with backing store of various - types—unbacked, swap-backed, physical device-backed, or - file-backed storage. Since the filesystem uses the same VM objects to - manage in-core data relating to files, the result is a unified buffer - cache.</para> - - <para>VM objects can be <emphasis>shadowed</emphasis>. That is, they - can be stacked on top of each other. For example, you might have a - swap-backed VM object stacked on top of a file-backed VM object in - order to implement a MAP_PRIVATE mmap()ing. This stacking is also - used to implement various sharing properties, including, - copy-on-write, for forked address spaces.</para> - - <para>It should be noted that a <literal>vm_page_t</literal> can only be - associated with one VM object at a time. The VM object shadowing - implements the perceived sharing of the same page across multiple - instances.</para> - </sect2> - - <sect2> - <title>Filesystem I/O—<literal>struct buf</literal></title> - - <para>vnode-backed VM objects, such as file-backed objects, generally - need to maintain their own clean/dirty info independent from the VM - system's idea of clean/dirty. For example, when the VM system decides - to synchronize a physical page to its backing store, the VM system - needs to mark the page clean before the page is actually written to - its backing s tore. Additionally, filesystems need to be able to map - portions of a file or file metadata into KVM in order to operate on - it.</para> - - <para>The entities used to manage this are known as filesystem buffers, - <literal>struct buf</literal>'s, and also known as - <literal>bp</literal>'s. When a filesystem needs to operate on a - portion of a VM object, it typically maps part of the object into a - struct buf and the maps the pages in the struct buf into KVM. In the - same manner, disk I/O is typically issued by mapping portions of - objects into buffer structures and then issuing the I/O on the buffer - structures. The underlying vm_page_t's are typically busied for the - duration of the I/O. Filesystem buffers also have their own notion of - being busy, which is useful to filesystem driver code which would - rather operate on filesystem buffers instead of hard VM pages.</para> - - <para>FreeBSD reserves a limited amount of KVM to hold mappings from - struct bufs, but it should be made clear that this KVM is used solely - to hold mappings and does not limit the ability to cache data. - Physical data caching is strictly a function of - <literal>vm_page_t</literal>'s, not filesystem buffers. However, - since filesystem buffers are used placehold I/O, they do inherently - limit the amount of concurrent I/O possible. As there are usually a - few thousand filesystem buffers available, this is not usually a - problem.</para> - </sect2> - - <sect2> - <title>Mapping Page Tables - vm_map_t, vm_entry_t</title> - - <para>FreeBSD separates the physical page table topology from the VM - system. All hard per-process page tables can be reconstructed on the - fly and are usually considered throwaway. Special page tables such as - those managing KVM are typically permanently preallocated. These page - tables are not throwaway.</para> - - <para>FreeBSD associates portions of vm_objects with address ranges in - virtual memory through <literal>vm_map_t</literal> and - <literal>vm_entry_t</literal> structures. Page tables are directly - synthesized from the - <literal>vm_map_t</literal>/<literal>vm_entry_t</literal>/ - <literal>vm_object_t</literal> hierarchy. Remember when I mentioned - that physical pages are only directly associated with a - <literal>vm_object</literal>. Well, that isn't quite true. - <literal>vm_page_t</literal>'s are also linked into page tables that - they are actively associated with. One <literal>vm_page_t</literal> - can be linked into several <emphasis>pmaps</emphasis>, as page tables - are called. However, the hierarchical association holds so all - references to the same page in the same object reference the same - <literal>vm_page_t</literal> and thus give us buffer cache unification - across the board.</para> - </sect2> - - <sect2> - <title>KVM Memory Mapping</title> - - <para>FreeBSD uses KVM to hold various kernel structures. The single - largest entity held in KVM is the filesystem buffer cache. That is, - mappings relating to <literal>struct buf</literal> entities.</para> - - <para>Unlike Linux, FreeBSD does NOT map all of physical memory into - KVM. This means that FreeBSD can handle memory configurations up to - 4G on 32 bit platforms. In fact, if the mmu were capable of it, - FreeBSD could theoretically handle memory configurations up to 8TB on - a 32 bit platform. However, since most 32 bit platforms are only - capable of mapping 4GB of ram, this is a moot point.</para> - - <para>KVM is managed through several mechanisms. The main mechanism - used to manage KVM is the <emphasis>zone allocator</emphasis>. The - zone allocator takes a chunk of KVM and splits it up into - constant-sized blocks of memory in order to allocate a specific type - of structure. You can use <command>vmstat -m</command> to get an - overview of current KVM utilization broken down by zone.</para> - </sect2> - - <sect2> - <title>Tuning the FreeBSD VM system</title> - - <para>A concerted effort has been made to make the FreeBSD kernel - dynamically tune itself. Typically you do not need to mess with - anything beyond the <literal>maxusers</literal> and - <literal>NMBCLUSTERS</literal> kernel config options. That is, kernel - compilation options specified in (typically) - <filename>/usr/src/sys/i386/conf/<replaceable>CONFIG_FILE</replaceable></filename>. - A description of all available kernel configuration options can be - found in <filename>/usr/src/sys/i386/conf/LINT</filename>.</para> - - <para>In a large system configuration you may wish to increase - <literal>maxusers</literal>. Values typically range from 10 to 128. - Note that raising <literal>maxusers</literal> too high can cause the - system to overflow available KVM resulting in unpredictable operation. - It is better to leave maxusers at some reasonable number and add other - options, such as <literal>NMBCLUSTERS</literal>, to increase specific - resources.</para> - - <para>If your system is going to use the network heavily, you may want - to increase <literal>NMBCLUSTERS</literal>. Typical values range from - 1024 to 4096.</para> - - <para>The <literal>NBUF</literal> parameter is also traditionally used - to scale the system. This parameter determines the amount of KVA the - system can use to map filesystem buffers for I/O. Note that this - parameter has nothing whatsoever to do with the unified buffer cache! - This parameter is dynamically tuned in 3.0-CURRENT and later kernels - and should generally not be adjusted manually. We recommend that you - <emphasis>not</emphasis> try to specify an <literal>NBUF</literal> - parameter. Let the system pick it. Too small a value can result in - extremely inefficient filesystem operation while too large a value can - starve the page queues by causing too many pages to become wired - down.</para> - - <para>By default, FreeBSD kernels are not optimized. You can set - debugging and optimization flags with the - <literal>makeoptions</literal> directive in the kernel configuration. - Note that you should not use <option>-g</option> unless you can - accommodate the large (typically 7 MB+) kernels that result.</para> - - <programlisting>makeoptions DEBUG="-g" -makeoptions COPTFLAGS="-O -pipe"</programlisting> - - <para>Sysctl provides a way to tune kernel parameters at run-time. You - typically do not need to mess with any of the sysctl variables, - especially the VM related ones.</para> - - <para>Run time VM and system tuning is relatively straightforward. - First, use softupdates on your UFS/FFS filesystems whenever possible. - <filename>/usr/src/contrib/sys/softupdates/README</filename> contains - instructions (and restrictions) on how to configure it up.</para> - - <para>Second, configure sufficient swap. You should have a swap - partition configured on each physical disk, up to four, even on your - <quote>work</quote> disks. You should have at least 2x the swap space - as you have main memory, and possibly even more if you do not have a - lot of memory. You should also size your swap partition based on the - maximum memory configuration you ever intend to put on the machine so - you do not have to repartition your disks later on. If you want to be - able to accommodate a crash dump, your first swap partition must be at - least as large as main memory and <filename>/var/crash</filename> must - have sufficient free space to hold the dump.</para> - - <para>NFS-based swap is perfectly acceptable on -4.x or later systems, - but you must be aware that the NFS server will take the brunt of the - paging load.</para> - </sect2> - </sect1> - -</chapter> diff --git a/en_US.ISO8859-1/books/handbook/basics/disk-layout.kil b/en_US.ISO8859-1/books/handbook/basics/disk-layout.kil Binary files differdeleted file mode 100644 index 85820c2878..0000000000 --- a/en_US.ISO8859-1/books/handbook/basics/disk-layout.kil +++ /dev/null diff --git a/en_US.ISO8859-1/books/handbook/book.sgml b/en_US.ISO8859-1/books/handbook/book.sgml index f07264b320..1ff7706f47 100644 --- a/en_US.ISO8859-1/books/handbook/book.sgml +++ b/en_US.ISO8859-1/books/handbook/book.sgml @@ -1,7 +1,7 @@ <!-- The FreeBSD Documentation Project - $FreeBSD: doc/en_US.ISO8859-1/books/handbook/book.sgml,v 1.110 2001/08/04 19:32:09 jim Exp $ + $FreeBSD: doc/en_US.ISO8859-1/books/handbook/book.sgml,v 1.114 2001/09/18 04:14:43 murray Exp $ --> <!DOCTYPE BOOK PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [ @@ -18,13 +18,13 @@ <!ENTITY % authors PUBLIC "-//FreeBSD//ENTITIES DocBook Author Entities//EN"> %authors; <!ENTITY % mailing-lists PUBLIC "-//FreeBSD//ENTITIES DocBook Mailing List Entities//EN"> %mailing-lists; -<!ENTITY % newsgroups SYSTEM "newsgroups.ent"> %newsgroups; +<!ENTITY % newsgroups PUBLIC "-//FreeBSD//ENTITIES DocBook Newsgroup Entities//EN"> %newsgroups; <!ENTITY % not.published "INCLUDE"> <!-- The currently released version of FreeBSD. This value is used to create some links on web sites and such, so do NOT change it until it's really release time --> -<!ENTITY rel.current CDATA "4.3"> +<!ENTITY rel.current CDATA "4.4"> <!ENTITY % chap.introduction "IGNORE"> <!ENTITY % chap.install "IGNORE"> @@ -46,7 +46,6 @@ <!ENTITY % chap.advanced-networking "IGNORE"> <!ENTITY % chap.mail "IGNORE"> <!ENTITY % chap.cutting-edge "IGNORE"> -<!ENTITY % chap.contrib "IGNORE"> <!ENTITY % chap.policies "IGNORE"> <!ENTITY % chap.kerneldebug "IGNORE"> <!ENTITY % chap.linuxemu "IGNORE"> @@ -169,7 +168,6 @@ <![ %chap.security; [ &chap.security; ]]> <![ %chap.printing; [ &chap.printing; ]]> <![ %chap.disks; [ &chap.disks; ]]> - <![ %chap.backups; [ &chap.backups; ]]> <![ %chap.l10n; [ &chap.l10n; ]]> <![ %chap.sound; [ &chap.sound; ]]> <![ %chap.serialcomms; [ &chap.serialcomms; ]]> @@ -177,7 +175,6 @@ <![ %chap.advanced-networking; [ &chap.advanced-networking; ]]> <![ %chap.mail; [ &chap.mail; ]]> <![ %chap.cutting-edge; [ &chap.cutting-edge; ]]> - <![ %chap.contrib; [ &chap.contrib; ]]> <![ %chap.policies; [ &chap.policies; ]]> <![ %chap.kerneldebug; [ &chap.kerneldebug; ]]> <![ %chap.linuxemu; [ &chap.linuxemu; ]]> diff --git a/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml b/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml index c4b8b02501..0f8d1937b5 100644 --- a/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml +++ b/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml @@ -1,7 +1,7 @@ <!-- The FreeBSD Documentation Project - $FreeBSD: doc/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml,v 1.58 2001/08/14 23:02:37 logo Exp $ + $FreeBSD: doc/en_US.ISO8859-1/books/handbook/introduction/chapter.sgml,v 1.59 2001/08/16 18:35:03 chern Exp $ --> <chapter id="introduction"> @@ -34,8 +34,8 @@ read about <link linkend="history">the history of FreeBSD</link>, or the <link linkend="relnotes">current release</link>. If you are interested in contributing something to the Project (code, - hardware, unmarked bills), see the <link - linkend="contrib">contributing to FreeBSD</link> section.</para> + hardware, unmarked bills), see the <ulink url=" + http://www.FreeBSD.org/doc/en_US.ISO8859-1/articles/contributing/article.html">Contributing to FreeBSD</ulink> article.</para> </sect1> <sect1 id="nutshell"> @@ -767,8 +767,9 @@ <para>Providing code is not the only way of contributing to the project; for a more complete list of things that need - doing, please refer to the <link linkend="contrib">how to - contribute</link> section in this handbook.</para> + doing, please refer to the <ulink + url="http://www.FreeBSD.org">FreeBSD Project web + site</ulink>.</para> </listitem> </varlistentry> </variablelist> diff --git a/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml b/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml index c447e38c9c..3e320d91af 100644 --- a/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml +++ b/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml @@ -1,7 +1,7 @@ <!-- The FreeBSD Documentation Project - $FreeBSD: doc/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml,v 1.150 2001/09/02 11:16:16 murray Exp $ + $FreeBSD: doc/en_US.ISO8859-1/books/handbook/mirrors/chapter.sgml,v 1.155 2001/09/18 12:54:12 dcs Exp $ --> <appendix id="mirrors"> @@ -51,7 +51,7 @@ <listitem> <address> <otheraddr>Daemon News</otheraddr> - <street>2680 Bayshore Parkway, Suite 307</street> + <street>2672 Bayshore Parkway, Suite 610</street> <city>Mountain View</city>, <state>CA</state> <postcode>94043</postcode> <country>USA</country> Phone: <phone>+1 650 694-4949</phone> @@ -83,7 +83,7 @@ <listitem> <address> <otheraddr>Cylogistics</otheraddr> - <street>2680 Bayshore Parkway, Suite 307</street> + <street>2672 Bayshore Parkway, Suite 610</street> <city>Mountain View</city>, <state>CA</state> <postcode>94043</postcode> <country>USA</country> Phone: <phone>+1 650 694-4949</phone> @@ -1116,6 +1116,15 @@ </varlistentry> <varlistentry> + <term>RELENG_4_4</term> + + <listitem> + <para>The release branch for FreeBSD-4.4, used only + for security advisories and other seriously critical fixes.</para> + </listitem> + </varlistentry> + + <varlistentry> <term>RELENG_4_3</term> <listitem> @@ -1150,6 +1159,14 @@ <variablelist> <varlistentry> + <term>RELENG_4_4_0_RELEASE</term> + + <listitem> + <para>FreeBSD 4.4.</para> + </listitem> + </varlistentry> + + <varlistentry> <term>RELENG_4_3_0_RELEASE</term> <listitem> @@ -1985,6 +2002,16 @@ </varlistentry> <varlistentry> + <term>tag=RELENG_4_4</term> + + <listitem> + <para>The release branch for FreeBSD-4.4, used only + for security advisories and other seriously critical + fixes.</para> + </listitem> + </varlistentry> + + <varlistentry> <term>tag=RELENG_4_3</term> <listitem> @@ -2018,6 +2045,14 @@ <variablelist> <varlistentry> + <term>tag=RELENG_4_4_0_RELEASE</term> + + <listitem> + <para>FreeBSD 4.4.</para> + </listitem> + </varlistentry> + + <varlistentry> <term>tag=RELENG_4_3_0_RELEASE</term> <listitem> @@ -3296,6 +3331,11 @@ doc/ja_JP.eucJP</screen> <para>cvsup3.br.FreeBSD.org (maintainer <email>camposr@matrix.com.br</email>)</para> </listitem> + + <listitem> + <para>cvsup4.br.FreeBSD.org (maintainer + <email>cvsup@tcoip.com.br</email>)</para> + </listitem> </itemizedlist> </listitem> </varlistentry> @@ -3821,7 +3861,7 @@ doc/ja_JP.eucJP</screen> <itemizedlist> <listitem> <para>cvsup1.FreeBSD.org (maintainer - <email>skynyrd@opus.cts.cwu.edu</email>), Washington + <email>cwt@networks.cwu.edu</email>), Washington state</para> </listitem> @@ -3846,6 +3886,11 @@ doc/ja_JP.eucJP</screen> </listitem> <listitem> + <para>cvsup6.FreeBSD.org (maintainer + <email>cvsup@cvsup.adelphiacom.net</email>), Illinois</para> + </listitem> + + <listitem> <para>cvsup7.FreeBSD.org (maintainer <email>jdp@FreeBSD.org</email>), Washington state</para> </listitem> diff --git a/en_US.ISO8859-1/books/handbook/multimedia/Makefile b/en_US.ISO8859-1/books/handbook/multimedia/Makefile deleted file mode 100644 index 0ea7f84352..0000000000 --- a/en_US.ISO8859-1/books/handbook/multimedia/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Build the Handbook with just the content from this chapter. -# -# $FreeBSD$ -# - -CHAPTERS= sound/chapter.sgml - -VPATH= .. - -MASTERDOC= ${.CURDIR}/../${DOC}.${DOCBOOKSUFFIX} - -DOC_PREFIX?= ${.CURDIR}/../../../.. - -.include "../Makefile" diff --git a/en_US.ISO8859-1/books/handbook/multimedia/chapter.sgml b/en_US.ISO8859-1/books/handbook/multimedia/chapter.sgml deleted file mode 100644 index 5ceb0bf41c..0000000000 --- a/en_US.ISO8859-1/books/handbook/multimedia/chapter.sgml +++ /dev/null @@ -1,368 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD: doc/en_US.ISO8859-1/books/handbook/sound/chapter.sgml,v 1.15 2001/08/16 18:35:08 chern Exp $ ---> - -<chapter id="sound"> - <chapterinfo> - <authorgroup> - <author> - <firstname>Moses</firstname> - <surname>Moore</surname> - <contrib>Contributed by </contrib> - </author> - </authorgroup> - <!-- 20 November 2000 --> - </chapterinfo> - - <title>Sound</title> - - <sect1> - <title>Synopsis</title> - - <para>FreeBSD supports a wide variety of sound cards, allowing you - to enjoy high fidelity output from your computer. This includes - the ability to record and playback audio in the MPEG Audio Layer - 3 (MP3), WAV, and Ogg Vorbis formats as well as many other - formats. The FreeBSD Ports Collection also contains - applications allowing you to edit your recorded audio, add sound - effects, and control attached MIDI devices.</para> - -<!-- XXX we need to talk about ripping MP3s here. --> - - <para>After reading this chapter you will know:</para> - <itemizedlist> - <listitem><para>How to locate your sound card.</para></listitem> - <listitem><para>How to configure your system so that your sound card is - recognized.</para></listitem> - <listitem><para>Methods to test that your card is working using - sample applications.</para></listitem> - <listitem><para>How to troubleshoot your sound setup.</para></listitem> - </itemizedlist> - - <para>Before reading this chapter you should:</para> - - <itemizedlist> - <listitem><para>Know how to configure and install a new kernel (<xref - linkend="kernelconfig">).</para></listitem> - </itemizedlist> - </sect1> - - <sect1> - <title>Locating the Correct Device</title> - - <indexterm><primary>PCI</primary></indexterm> - <indexterm><primary>ISA</primary></indexterm> - <indexterm><primary>sound cards</primary></indexterm> - <para>Before you begin, you should know the model of the card you - have, the chip it uses, and whether it is a PCI or ISA card. - FreeBSD supports a wide variety of both PCI and ISA cards. If you - do not see your card in the following list, check the &man.pcm.4; - manual page. This is not a complete list; however, it does list - some of the most common cards.</para> - - <itemizedlist> - <listitem> - <para>Crystal 4237, 4236, 4232, 4231</para> - </listitem> - - <listitem> - <para>Yamaha OPL-SAx</para> - </listitem> - - <listitem> - <para>OPTi931</para> - </listitem> - - <listitem> - <para>Ensoniq AudioPCI 1370/1371</para> - </listitem> - - <listitem> - <para>ESS Solo-1/1E</para> - </listitem> - - <listitem> - <para>NeoMagic 256AV/ZX</para> - </listitem> - - <listitem> - <para>Sound Blaster Pro, 16, 32, AWE64, AWE128, Live</para> - </listitem> - - <listitem> - <para>Creative ViBRA16</para> - </listitem> - - <listitem> - <para>Advanced Asound 100, 110, and Logic ALS120</para> - </listitem> - - <listitem> - <para>ES 1868, 1869, 1879, 1888</para> - </listitem> - - <listitem> - <para>Gravis UltraSound</para> - </listitem> - - <listitem> - <para>Aureal Vortex 1 or 2</para> - </listitem> - </itemizedlist> - - <indexterm> - <primary>kernel</primary> - <secondary>configuration</secondary> - </indexterm> - <para>The driver you use in your kernel depends on the kind of card - you have. The sections below provide more information and what - you will need to add to your <link linkend="kernelconfig">kernel - configuration</link>.</para> - - <sect2> - <title>Creative, Advance, and ESS Sound Cards</title> - - <para>If you have one of the above cards, you will need to - add</para> - - <programlisting>device pcm</programlisting> - - <para>to your kernel. If you have a PnP ISA card, you will also - need to add</para> - - <programlisting>device sbc</programlisting> - - <para>to your kernel. For a non-PnP ISA card, add</para> - - <programlisting>device pcm</programlisting> - - <para>and</para> - - <programlisting>device sbc0 at isa? port0x220 irq 5 drq 1 flags 0x15</programlisting> - - <para>to your kernel. Those are the default settings. You may - need to change the IRQ, etc. See the &man.sbc.4; manual page for - more information.</para> - - <note> - <para>The Sound Blaster Live is not supported under FreeBSD 4.0 - without a patch, which this document will not cover. It is - recommended that you update to the latest -STABLE before - trying to use this card.</para> - </note> - </sect2> - - <sect2> - <title>Gravis UltraSound Cards</title> - - <para>For a PnP ISA card, you will need to add</para> - - <programlisting>device pcm</programlisting> - - <para>and</para> - - <programlisting>device gusc</programlisting> - - <para>to your kernel. If you have a non-PnP ISA card, you will - need to add</para> - - <programlisting>device pcm</programlisting> - - <para>and</para> - - <programlisting>device gus0 at isa? port 0x220 irq 5 drq 1 flags 0x13</programlisting> - - <para>to your kernel. You may need to change the IRQ, etc. See - the &man.gusc.4; manual page for more information.</para> - </sect2> - - <sect2> - <title>Crystal Sound Cards</title> - - <para>For Crystal cards, you will need both</para> - - <programlisting>device pcm</programlisting> - - <para>and</para> - - <programlisting>device csa</programlisting> - - <para>in your kernel.</para> - </sect2> - - <sect2> - <title>Generic Support</title> - - <para>For PnP ISA or PCI cards, you will need to add</para> - - <programlisting>device pcm</programlisting> - - <para>to your kernel configuration. If you have a non-PnP ISA - sound card that does not have a bridge driver, you will need - to add</para> - - <programlisting>device pcm0 at isa? irq 10 drq 1 flags 0x0</programlisting> - - <para>to your kernel configuration. You may need to change the - IRQ, etc., to match your hardware configuration.</para> - </sect2> - </sect1> - - <sect1> - <title>Recompiling the Kernel</title> - - <para>After adding the driver(s) you need to your kernel - configuration, you will need to recompile your kernel. Please see - <xref linkend="kernelconfig-building"> of the handbook for - more information.</para> - </sect1> - - <sect1> - <title>Creating and Testing the Device Nodes</title> - - <indexterm><primary>device nodes</primary></indexterm> - <para>After you reboot, log in and run <command>cat - /dev/sndstat</command>. You should see output similar to the - following:</para> - - <programlisting>FreeBSD Audio Driver (newpcm) Sep 21 2000 18:29:53 -Installed devices: -pcm0: <Aureal Vortex 8830> at memory 0xfeb40000 irq 5 (4p/1r +channels duplex)</programlisting> - - <para>If you see an error message, something went wrong earlier. If - that happens, go through your kernel configuration file again and - make sure you chose the correct device.</para> - - <para>If it reported no errors and returned - <devicename>pcm0</devicename>, <command>su</command> to - <username>root</username> and do the following:</para> - - <screen>&prompt.root; <userinput>cd /dev</userinput> -&prompt.root; <userinput>sh MAKEDEV snd0</userinput></screen> - - <para>If it reported no errors and returned - <devicename>pcm1</devicename>, <command>su</command> to - <username>root</username> and do the following:</para> - - <screen>&prompt.root; <userinput>cd /dev</userinput> -&prompt.root; <userinput>sh MAKEDEV snd1</userinput></screen> - - <para>Please note that either of the above commands will - <emphasis>not</emphasis> create a - <devicename>/dev/snd</devicename> device! Instead it creates a - group of device nodes including:</para> - - <informaltable frame="none"> - <tgroup cols="2"> - <thead> - <row> - <entry>Device</entry> - <entry>Description</entry> - </row> - </thead> - - <tbody> - <row> - <entry><devicename>/dev/audio</devicename></entry> - <entry>SPARC-compatible audio device</entry> - </row> - - <row> - <entry><devicename>/dev/dsp</devicename></entry> - <entry>Digitized voice device</entry> - </row> - - <row> - <entry><devicename>/dev/dspW</devicename></entry> - <entry>Like <devicename>/dev/dsp</devicename>, but 16 bits - per sample</entry> - </row> - - <row> - <entry><devicename>/dev/midi</devicename></entry> - <entry>Raw midi access device</entry> - </row> - - <row> - <entry><devicename>/dev/mixer</devicename></entry> - <entry>Control port mixer device</entry> - </row> - - <row> - <entry><devicename>/dev/music</devicename></entry> - <entry>Level 2 sequencer interface</entry> - </row> - - <row> - <entry><devicename>/dev/sequencer</devicename></entry> - <entry>Sequencer device</entry> - </row> - - <row> - <entry><devicename>/dev/pss</devicename></entry> - <entry>Programmable device interface</entry> - </row> - </tbody> - </tgroup> - </informaltable> - - <para>If all goes well, you should now have a functioning sound - card. If you do not, see the next section.</para> - </sect1> - - <sect1> - <title>Common Problems</title> - - <qandaset> - <indexterm><primary>device node</primary></indexterm> - <qandaentry> - <question> - <para>I get an unsupported subdevice XX error!</para> - </question> - - <answer> - <para>One or more of the device nodes was not created - correctly. Repeat the steps above.</para> - </answer> - </qandaentry> - - <indexterm><primary>I/O port</primary></indexterm> - <qandaentry> - <question> - <para>I get a sb_dspwr(XX) timed out error!</para> - </question> - - <answer> - <para>The I/O port is not set correctly.</para> - </answer> - </qandaentry> - - <indexterm><primary>IRQ</primary></indexterm> - <qandaentry> - <question> - <para>I get a bad irq XX error!</para> - </question> - - <answer> - <para>The IRQ is set incorrectly. Make sure that the set IRQ - and the sound IRQ are the same.</para> - </answer> - </qandaentry> - - <qandaentry> - <question> - <para>I get a <errorname>xxx: gus pcm not attached, out of - memory</errorname> - error. What causes that?</para> - </question> - - <answer> - <para>If this happens, it is because there is not enough - available memory to use the device.</para> - </answer> - </qandaentry> - </qandaset> - </sect1> -</chapter> diff --git a/en_US.ISO8859-1/share/sgml/newsgroups.ent b/en_US.ISO8859-1/share/sgml/newsgroups.ent new file mode 100644 index 0000000000..04f5cc7c7b --- /dev/null +++ b/en_US.ISO8859-1/share/sgml/newsgroups.ent @@ -0,0 +1,10 @@ +<!-- + Names of FreeBSD newsgroups + + $FreeBSD: doc/en_US.ISO8859-1/books/handbook/newsgroups.ent,v 1.2 1999/09/06 06:52:47 peter Exp $ +--> + +<!ENTITY ng.misc "the + <ulink url='news:comp.unix.bsd.freebsd.misc'>comp.unix.bsd.freebsd.misc</ulink> + newsgroup"> + |