1 /* 2 * i2c 3 * 4 * Copyright © 1998, 2003 Vita Nuova Limited. 5 */ 6 7 #include "u.h" 8 #include "../port/lib.h" 9 #include "mem.h" 10 #include "dat.h" 11 #include "fns.h" 12 #include "io.h" 13 #include "../port/error.h" 14 15 typedef struct I2Cdir I2Cdir; 16 17 enum{ 18 Qdir, 19 Qdata, 20 Qctl, 21 }; 22 23 static 24 Dirtab i2ctab[]={ 25 ".", {Qdir, 0, QTDIR}, 0, 0555, 26 "i2cdata", {Qdata, 0}, 256, 0660, 27 "i2cctl", {Qctl, 0}, 0, 0660, 28 }; 29 30 struct I2Cdir { 31 Ref; 32 I2Cdev; 33 Dirtab tab[nelem(i2ctab)]; 34 }; 35 36 static void 37 i2creset(void) 38 { 39 i2csetup(0); 40 } 41 42 static Chan* 43 i2cattach(char* spec) 44 { 45 char *s; 46 ulong addr; 47 I2Cdir *d; 48 Chan *c; 49 50 addr = strtoul(spec, &s, 16); 51 if(*spec == 0 || *s || addr >= (1<<10)) 52 error("invalid i2c address"); 53 d = malloc(sizeof(I2Cdir)); 54 if(d == nil) 55 error(Enomem); 56 d->ref = 1; 57 d->addr = addr; 58 d->salen = 0; 59 d->tenbit = addr >= 128; 60 memmove(d->tab, i2ctab, sizeof(d->tab)); 61 sprint(d->tab[1].name, "i2c.%lux.data", addr); 62 sprint(d->tab[2].name, "i2c.%lux.ctl", addr); 63 64 c = devattach('J', spec); 65 c->aux = d; 66 return c; 67 } 68 69 static Walkqid* 70 i2cwalk(Chan* c, Chan *nc, char **name, int nname) 71 { 72 Walkqid *wq; 73 I2Cdir *d; 74 75 d = c->aux; 76 wq = devwalk(c, nc, name, nname, d->tab, nelem(d->tab), devgen); 77 if(wq != nil && wq->clone != nil && wq->clone != c) 78 incref(d); 79 return wq; 80 } 81 82 static int 83 i2cstat(Chan* c, uchar *dp, int n) 84 { 85 I2Cdir *d; 86 87 d = c->aux; 88 return devstat(c, dp, n, d->tab, nelem(d->tab), devgen); 89 } 90 91 static Chan* 92 i2copen(Chan* c, int omode) 93 { 94 I2Cdir *d; 95 96 d = c->aux; 97 return devopen(c, omode, d->tab, nelem(d->tab), devgen); 98 } 99 100 static void 101 i2cclose(Chan *c) 102 { 103 I2Cdir *d; 104 105 d = c->aux; 106 if(decref(d) == 0) 107 free(d); 108 } 109 110 static long 111 i2cread(Chan *c, void *a, long n, vlong offset) 112 { 113 I2Cdir *d; 114 char *s, *e; 115 ulong len; 116 117 d = c->aux; 118 switch((ulong)c->qid.path){ 119 case Qdir: 120 return devdirread(c, a, n, d->tab, nelem(d->tab), devgen); 121 case Qdata: 122 len = d->tab[1].length; 123 if(offset+n >= len){ 124 n = len - offset; 125 if(n <= 0) 126 return 0; 127 } 128 n = i2crecv(d, a, n, offset); 129 break; 130 case Qctl: 131 s = smalloc(READSTR); 132 if(waserror()){ 133 free(s); 134 nexterror(); 135 } 136 e = seprint(s, s+READSTR, "size %lud\n", (ulong)d->tab[1].length); 137 if(d->salen) 138 e = seprint(e, s+READSTR, "subaddress %d\n", d->salen); 139 if(d->tenbit) 140 seprint(e, s+READSTR, "a10\n"); 141 n = readstr(offset, a, n, s); 142 poperror(); 143 free(s); 144 return n; 145 default: 146 n=0; 147 break; 148 } 149 return n; 150 } 151 152 static long 153 i2cwrite(Chan *c, void *a, long n, vlong offset) 154 { 155 I2Cdir *d; 156 long len; 157 Cmdbuf *cb; 158 159 USED(offset); 160 switch((ulong)c->qid.path){ 161 case Qdata: 162 d = c->aux; 163 len = d->tab[1].length; 164 if(offset+n >= len){ 165 n = len - offset; 166 if(n <= 0) 167 return 0; 168 } 169 n = i2csend(d, a, n, offset); 170 break; 171 case Qctl: 172 cb = parsecmd(a, n); 173 if(waserror()){ 174 free(cb); 175 nexterror(); 176 } 177 if(cb->nf < 1) 178 error(Ebadctl); 179 d = c->aux; 180 if(strcmp(cb->f[0], "subaddress") == 0){ 181 if(cb->nf > 1){ 182 len = strtol(cb->f[1], nil, 0); 183 if(len <= 0) 184 len = 0; 185 if(len > 4) 186 cmderror(cb, "subaddress too long"); 187 }else 188 len = 1; 189 d->salen = len; 190 }else if(cb->nf > 1 && strcmp(cb->f[0], "size") == 0){ 191 len = strtol(cb->f[1], nil, 0); 192 if(len < 0) 193 cmderror(cb, "size is negative"); 194 d->tab[1].length = len; 195 }else if(strcmp(cb->f[0], "a10") == 0) 196 d->tenbit = 1; 197 else 198 cmderror(cb, "unknown control request"); 199 poperror(); 200 free(cb); 201 break; 202 default: 203 error(Ebadusefd); 204 } 205 return n; 206 } 207 208 Dev i2cdevtab = { 209 'J', 210 "i2c", 211 212 i2creset, 213 devinit, 214 devshutdown, 215 i2cattach, 216 i2cwalk, 217 i2cstat, 218 i2copen, 219 devcreate, 220 i2cclose, 221 i2cread, 222 devbread, 223 i2cwrite, 224 devbwrite, 225 devremove, 226 devwstat, 227 }; 228