devarch.c 6.6 KB

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