The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mtx/devarch.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "../port/error.h"
    8 
    9 typedef struct IOMap IOMap;
   10 struct IOMap
   11 {
   12         IOMap   *next;
   13         char    tag[13];
   14         ulong   start;
   15         ulong   end;
   16 };
   17 
   18 static struct
   19 {
   20         Lock;
   21         IOMap   *m;
   22         IOMap   *free;
   23         IOMap   maps[32];               // some initial free maps
   24 
   25         QLock   ql;                     // lock for reading map
   26 } iomap;
   27 
   28 enum {
   29         Qdir = 0,
   30         Qioalloc = 1,
   31         Qiob,
   32         Qiow,
   33         Qiol,
   34         Qbase,
   35 
   36         Qmax = 16,
   37 };
   38 
   39 typedef long Rdwrfn(Chan*, void*, long, vlong);
   40 
   41 static Rdwrfn *readfn[Qmax];
   42 static Rdwrfn *writefn[Qmax];
   43 
   44 static Dirtab archdir[] = {
   45         ".",    { Qdir, 0, QTDIR },     0,      0555,
   46         "ioalloc",      { Qioalloc, 0 },        0,      0444,
   47         "iob",          { Qiob, 0 },            0,      0660,
   48         "iow",          { Qiow, 0 },            0,      0660,
   49         "iol",          { Qiol, 0 },            0,      0660,
   50 };
   51 Lock archwlock; /* the lock is only for changing archdir */
   52 int narchdir = Qbase;
   53 int (*_pcmspecial)(char *, ISAConf *);
   54 void (*_pcmspecialclose)(int);
   55 
   56 /*
   57  * Add a file to the #P listing.  Once added, you can't delete it.
   58  * You can't add a file with the same name as one already there,
   59  * and you get a pointer to the Dirtab entry so you can do things
   60  * like change the Qid version.  Changing the Qid path is disallowed.
   61  */
   62 Dirtab*
   63 addarchfile(char *name, int perm, Rdwrfn *rdfn, Rdwrfn *wrfn)
   64 {
   65         int i;
   66         Dirtab d;
   67         Dirtab *dp;
   68 
   69         memset(&d, 0, sizeof d);
   70         strcpy(d.name, name);
   71         d.perm = perm;
   72 
   73         lock(&archwlock);
   74         if(narchdir >= Qmax){
   75                 unlock(&archwlock);
   76                 return nil;
   77         }
   78 
   79         for(i=0; i<narchdir; i++)
   80                 if(strcmp(archdir[i].name, name) == 0){
   81                         unlock(&archwlock);
   82                         return nil;
   83                 }
   84 
   85         d.qid.path = narchdir;
   86         archdir[narchdir] = d;
   87         readfn[narchdir] = rdfn;
   88         writefn[narchdir] = wrfn;
   89         dp = &archdir[narchdir++];
   90         unlock(&archwlock);
   91 
   92         return dp;
   93 }
   94 
   95 void
   96 ioinit(void)
   97 {
   98         int i;
   99 
  100         for(i = 0; i < nelem(iomap.maps)-1; i++)
  101                 iomap.maps[i].next = &iomap.maps[i+1];
  102         iomap.maps[i].next = nil;
  103         iomap.free = iomap.maps;
  104 
  105         // a dummy entry at 2^17
  106         ioalloc(0x20000, 1, 0, "dummy");
  107 }
  108 
  109 //
  110 //      alloc some io port space and remember who it was
  111 //      alloced to.  if port < 0, find a free region.
  112 //
  113 int
  114 ioalloc(int port, int size, int align, char *tag)
  115 {
  116         IOMap *m, **l;
  117         int i;
  118 
  119         lock(&iomap);
  120         if(port < 0){
  121                 // find a free port above 0x400 and below 0x1000
  122                 port = 0x400;
  123                 for(l = &iomap.m; *l; l = &(*l)->next){
  124                         m = *l;
  125                         i = m->start - port;
  126                         if(i > size)
  127                                 break;
  128                         if(align > 0)
  129                                 port = ((port+align-1)/align)*align;
  130                         else
  131                                 port = m->end;
  132                 }
  133                 if(*l == nil){
  134                         unlock(&iomap);
  135                         return -1;
  136                 }
  137         } else {
  138                 // see if the space clashes with previously allocated ports
  139                 for(l = &iomap.m; *l; l = &(*l)->next){
  140                         m = *l;
  141                         if(m->end <= port)
  142                                 continue;
  143                         if(m->start >= port+size)
  144                                 break;
  145                         unlock(&iomap);
  146                         return -1;
  147                 }
  148         }
  149         m = iomap.free;
  150         if(m == nil){
  151                 print("ioalloc: out of maps");
  152                 unlock(&iomap);
  153                 return port;
  154         }
  155         iomap.free = m->next;
  156         m->next = *l;
  157         m->start = port;
  158         m->end = port + size;
  159         strncpy(m->tag, tag, sizeof(m->tag));
  160         m->tag[sizeof(m->tag)-1] = 0;
  161         *l = m;
  162 
  163         archdir[0].qid.vers++;
  164 
  165         unlock(&iomap);
  166         return m->start;
  167 }
  168 
  169 void
  170 iofree(int port)
  171 {
  172         IOMap *m, **l;
  173 
  174         lock(&iomap);
  175         for(l = &iomap.m; *l; l = &(*l)->next){
  176                 if((*l)->start == port){
  177                         m = *l;
  178                         *l = m->next;
  179                         m->next = iomap.free;
  180                         iomap.free = m;
  181                         break;
  182                 }
  183                 if((*l)->start > port)
  184                         break;
  185         }
  186         archdir[0].qid.vers++;
  187         unlock(&iomap);
  188 }
  189 
  190 int
  191 iounused(int start, int end)
  192 {
  193         IOMap *m;
  194 
  195         for(m = iomap.m; m; m = m->next){
  196                 if(start >= m->start && start < m->end
  197                 || start <= m->start && end > m->start)
  198                         return 0; 
  199         }
  200         return 1;
  201 }
  202 
  203 static void
  204 checkport(int start, int end)
  205 {
  206         /* standard vga regs are OK */
  207         if(start >= 0x2b0 && end <= 0x2df+1)
  208                 return;
  209         if(start >= 0x3c0 && end <= 0x3da+1)
  210                 return;
  211 
  212         if(iounused(start, end))
  213                 return;
  214         error(Eperm);
  215 }
  216 
  217 static Chan*
  218 archattach(char* spec)
  219 {
  220         return devattach('P', spec);
  221 }
  222 
  223 Walkqid*
  224 archwalk(Chan* c, Chan *nc, char** name, int nname)
  225 {
  226         return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
  227 }
  228 
  229 static int
  230 archstat(Chan* c, uchar* dp, int n)
  231 {
  232         return devstat(c, dp, n, archdir, narchdir, devgen);
  233 }
  234 
  235 static Chan*
  236 archopen(Chan* c, int omode)
  237 {
  238         return devopen(c, omode, archdir, nelem(archdir), devgen);
  239 }
  240 
  241 static void
  242 archclose(Chan*)
  243 {
  244 }
  245 
  246 enum
  247 {
  248         Linelen= 31,
  249 };
  250 
  251 static long
  252 archread(Chan *c, void *a, long n, vlong offset)
  253 {
  254         char buf[Linelen+1], *p;
  255         int port;
  256         ushort *sp;
  257         ulong *lp;
  258         IOMap *m;
  259         Rdwrfn *fn;
  260 
  261         switch((ulong)c->qid.path){
  262 
  263         case Qdir:
  264                 return devdirread(c, a, n, archdir, nelem(archdir), devgen);
  265 
  266         case Qiob:
  267                 port = offset;
  268                 checkport(offset, offset+n);
  269                 for(p = a; port < offset+n; port++)
  270                         *p++ = inb(port);
  271                 return n;
  272 
  273         case Qiow:
  274                 if((n & 0x01) || (offset & 0x01))
  275                         error(Ebadarg);
  276                 checkport(offset, offset+n+1);
  277                 n /= 2;
  278                 sp = a;
  279                 for(port = offset; port < offset+n; port += 2)
  280                         *sp++ = ins(port);
  281                 return n*2;
  282 
  283         case Qiol:
  284                 if((n & 0x03) || (offset & 0x03))
  285                         error(Ebadarg);
  286                 checkport(offset, offset+n+3);
  287                 n /= 4;
  288                 lp = a;
  289                 for(port = offset; port < offset+n; port += 4)
  290                         *lp++ = inl(port);
  291                 return n*4;
  292 
  293         case Qioalloc:
  294                 break;
  295 
  296         default:
  297                 if(c->qid.path < narchdir && (fn = readfn[c->qid.path]))
  298                         return fn(c, a, n, offset);
  299                 error(Eperm);
  300                 break;
  301         }
  302 
  303         offset = offset/Linelen;
  304         n = n/Linelen;
  305         p = a;
  306         lock(&iomap);
  307         for(m = iomap.m; n > 0 && m != nil; m = m->next){
  308                 if(offset-- > 0)
  309                         continue;
  310                 if(strcmp(m->tag, "dummy") == 0)
  311                         break;
  312                 sprint(buf, "%8lux %8lux %-12.12s\n", m->start, m->end-1, m->tag);
  313                 memmove(p, buf, Linelen);
  314                 p += Linelen;
  315                 n--;
  316         }
  317         unlock(&iomap);
  318 
  319         return p - (char*)a;
  320 }
  321 
  322 static long
  323 archwrite(Chan *c, void *a, long n, vlong offset)
  324 {
  325         char *p;
  326         int port;
  327         ushort *sp;
  328         ulong *lp;
  329         Rdwrfn *fn;
  330 
  331         switch((ulong)c->qid.path){
  332 
  333         case Qiob:
  334                 p = a;
  335                 checkport(offset, offset+n);
  336                 for(port = offset; port < offset+n; port++)
  337                         outb(port, *p++);
  338                 return n;
  339 
  340         case Qiow:
  341                 if((n & 01) || (offset & 01))
  342                         error(Ebadarg);
  343                 checkport(offset, offset+n+1);
  344                 n /= 2;
  345                 sp = a;
  346                 for(port = offset; port < offset+n; port += 2)
  347                         outs(port, *sp++);
  348                 return n*2;
  349 
  350         case Qiol:
  351                 if((n & 0x03) || (offset & 0x03))
  352                         error(Ebadarg);
  353                 checkport(offset, offset+n+3);
  354                 n /= 4;
  355                 lp = a;
  356                 for(port = offset; port < offset+n; port += 4)
  357                         outl(port, *lp++);
  358                 return n*4;
  359 
  360         default:
  361                 if(c->qid.path < narchdir && (fn = writefn[c->qid.path]))
  362                         return fn(c, a, n, offset);
  363                 error(Eperm);
  364                 break;
  365         }
  366         return 0;
  367 }
  368 
  369 Dev archdevtab = {
  370         'P',
  371         "arch",
  372 
  373         devreset,
  374         devinit,
  375         devshutdown,
  376         archattach,
  377         archwalk,
  378         archstat,
  379         archopen,
  380         devcreate,
  381         archclose,
  382         archread,
  383         devbread,
  384         archwrite,
  385         devbwrite,
  386         devremove,
  387         devwstat,
  388 };
  389 
  390 int
  391 pcmspecial(char *idstr, ISAConf *isa)
  392 {
  393         return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
  394 }
  395 
  396 void
  397 pcmspecialclose(int a)
  398 {
  399         if (_pcmspecialclose != nil)
  400                 _pcmspecialclose(a);
  401 }

Cache object: 06f06fb2271867d912921c2e90e71289


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.