Please wait until the page is fully downloaded and then press the "Expand" button or the blue line numbers.
0116000 /*
0116001 * upsock_0.c
0116002 *
0116003 * This file is used to Power up pc card socket 0 and initialize the socket.
0116004 * These must be down when the socket 0 is power down and before pc card driver
0116005 * begins to initialize the pc card.
0116006 *
0116007 * Created: Oct 2004 by Wangzhi <quakewang@mail.whut.edu.cn>
0116008 * Referenced: enable.c, ibmeth.c created by Philip Homburg
0116009 * misc.c by Kees J Bot
0116010 *
0116011 */
0116012
0116013 #include <sys/types.h>
0116014 #include <errno.h>
0116015 #include <fcntl.h>
0116016 #include <stdio.h>
0116017 #include <stdlib.h>
0116018 #include <string.h>
0116019 #include <unistd.h>
0116020 #include <sys/ioctl.h>
0116021 #include <ibm/portio.h>
0116022
0116023 #include "i82365.h"
0116024
0116025 #define MEM_BASE 0xdd000
0116026 #define ENV_VAR "TC589D"
0116027 #define EP_SET 3
0116028 static char PUNCT[] = ":,;.";
0116029
0116030 /* Declare vals and functions */
0116031 char *prog_name;
0116032 int socket;
0116033 u16_t index_port;
0116034 size_t curr_page= -1;
0116035 int mem_fd= -1;
0116036
0116037 int get_attr_byte(int socket, size_t addr);
0116038 void put_attr_byte(int socket, size_t addr, u8_t byte);
0116039 void map_page(int socket, int map, size_t page);
0116040 void map_io(int socket, int map, u16_t start, u16_t end, int b16);
0116041 u8_t in_reg(int socket, u8_t index);
0116042 void out_reg(int socket, u8_t index, u8_t value);
0116043 int env_parse(char*, char *fmt, int field, long *param, long min, long max);
0116044
0116045 int main(int argc, char *argv[])
0116046 {
0116047 u8_t c, g, gc, p, s;
0116048 long v;
0116049 static char env_var_fmt[]= "x:d";
0116050 long iobase, irq;
0116051 int i;
0116052
0116053 int result;
0116054 u8_t byte;
0116055
0116056 /* put this process' name into prog_name */
0116057 (prog_name=strrchr(argv[0],'/')) ? prog_name++ : (prog_name=argv[0]);
0116058
0116059 /* A normal user can not control hardware, but if you open the /dev/mem *
0116060 * device, you can control the hardware . *
0116061 * Try to get I/O privileges! */
0116062 if ((mem_fd= open("/dev/mem", O_RDWR)) == -1)
0116063 {
0116064 fprintf(stderr, "%s: unable to open '/dev/mem': %s
",
0116065 prog_name, strerror(errno));
0116066 exit(1);
0116067 }
0116068
0116069 /* The start address of the registers in PCMCIA controller */
0116070 index_port=I365_INDEX;
0116071
0116072 /* You can change the io range and irq(interrupt number) of *
0116073 * your PCMCIA controller socket 0. Certainly if you don't want to *
0116074 * not change them, we will use the default. The default is *
0116075 * I/O base is 0x300, interrupt handler number is: 5. *
0116076 * Why will I change them, for example: your another device may have *
0116077 * used them, so you must let your PC card use another one. *
0116078 * The following try to get iobase and irq value from *
0116079 * environment parameter. They are defined in /etc/rc. *
0116080 * The env_parse() function how to work see below. */
0116081
0116082 /* Get the I/O base address! */
0116083 if(env_parse(ENV_VAR, env_var_fmt, 0, &v, 0x0000, 0xffff) == EP_SET){
0116084 /* TC589D var is set */
0116085 iobase= v;
0116086 }else{
0116087 /* TC589D var is not set, use default */
0116088 iobase= 0x300;
0116089 }
0116090
0116091 /* Get the interrupt number! */
0116092 if(env_parse(ENV_VAR, env_var_fmt, 1, &v, 0, 15) == EP_SET){
0116093 /* TC589D var is set */
0116094 irq= v;
0116095 }else{
0116096 /* TC589D var is not set, use default */
0116097 irq= 5;
0116098 }
0116099
0116100 /* The following power up the PCMCIA socket 0 and make it work *
0116101 * If you want to know the detail, you must reference the PCMCIA *
0116102 * specification. This is for intel82365 compatible PCMCIA controller, *
0116103 * most of the PCMCIA controllers are intel82365 compatible, And there *
0116104 * another PCMCIA controllers. */
0116105 printf("Enabling the pc card socket 0 ......
");
0116106
0116107 /* Init the i82365 compliable pc card socket controller */
0116108 out_reg(socket, I365_PWR_CTL, 0x91);
0116109 out_reg(socket, I365_INT_GEN_CTL, 0xe0|(irq&0xf));
0116110
0116111 /* Enable the 3C589D Lan PC Card I/O */
0116112 put_attr_byte(socket, 0x10000/2, 0x80);
0116113 sleep(1);
0116114 put_attr_byte(socket, 0x10004/2, 0x0);
0116115 put_attr_byte(socket, 0x10006/2, 0x3);
0116116 put_attr_byte(socket, 0x10000/2, 0x41);
0116117
0116118 /* Map Pc Card I/O to Host I/O Space */
0116119 out_reg(socket, I365_IO_0_START_LOW, iobase & 0xff);
0116120 out_reg(socket, I365_IO_0_START_HIGH, (iobase>>8)& 0xff);
0116121 out_reg(socket, I365_IO_0_END_LOW, (iobase & 0xff) + 0xf);
0116122 out_reg(socket, I365_IO_0_END_HIGH, (iobase>>8)& 0xff);
0116123
0116124 /* enable I/O mapping */
0116125 out_reg(socket,I365_IO_WND_CTL,0x01);
0116126
0116127 /* other configurations */
0116128 out_reg(socket,I365_MAP_ENABLE,0x40);
0116129
0116130 exit(0);
0116131 }
0116132
0116133
0116134 /* The following read the attribute memory data! *
0116135 * If you want to know the detail, you must reference the PCMCIA *
0116136 * specification. */
0116137 int get_attr_byte(int socket, size_t addr)
0116138 {
0116139 size_t page;
0116140 u8_t byte;
0116141 int r;
0116142
0116143 addr *= 2;
0116144 page= addr >> 12;
0116145 if (page != curr_page)
0116146 map_page(socket, 1, page);
0116147 addr &= 0xfff;
0116148 if (lseek(mem_fd, (off_t)MEM_BASE+addr, SEEK_SET) == -1)
0116149 {
0116150 fprintf(stderr, "%s: lseek failed: %s
",
0116151 prog_name, strerror(errno));
0116152 exit(1);
0116153 }
0116154 if ((r= read(mem_fd, &byte, 1)) != 1)
0116155 {
0116156 fprintf(stderr, "%s: read failed: %s
",
0116157 prog_name, r == -1 ? strerror(errno) : "eof");
0116158 exit(1);
0116159 }
0116160 return byte;
0116161 }
0116162
0116163 /* The following write the attribute memory data! *
0116164 * If you want to know the detail, you must reference the PCMCIA *
0116165 * specification. */
0116166 void put_attr_byte(int socket, size_t addr, u8_t byte)
0116167 {
0116168 size_t page;
0116169 int r;
0116170
0116171 addr *= 2;
0116172 page= addr >> 12;
0116173 if (page != curr_page)
0116174 map_page(socket, 0, page);
0116175 addr &= 0xfff;
0116176 if (lseek(mem_fd, (off_t)MEM_BASE+addr, SEEK_SET) == -1)
0116177 {
0116178 fprintf(stderr, "%s: lseek failed: %s
",
0116179 prog_name, strerror(errno));
0116180 exit(1);
0116181 }
0116182 if ((r= write(mem_fd, &byte, 1)) != 1)
0116183 {
0116184 fprintf(stderr, "%s: write failed: %s
",
0116185 prog_name, r == -1 ? strerror(errno) : "eof");
0116186 exit(1);
0116187 }
0116188 }
0116189
0116190
0116191 /* The following map the PC card's attribute memory to the memory *
0116192 * of the computer, then we can read and write it. *
0116193 * If you want to know the detail, you must reference the PCMCIA *
0116194 * specification. */
0116195 void map_page(int socket, int map, size_t page)
0116196 {
0116197 size_t host_page, offset;
0116198
0116199 host_page= MEM_BASE >> 12;
0116200 offset= page-host_page;
0116201 out_reg(socket, I365_MEM_0_START_LOW + map*8, host_page & 0xff);
0116202 out_reg(socket, I365_MEM_0_START_HIGH + map*8, host_page >> 8);
0116203 out_reg(socket, I365_MEM_0_END_LOW + map*8, host_page & 0xff);
0116204 out_reg(socket, I365_MEM_0_END_HIGH + map*8, host_page >> 8);
0116205 out_reg(socket, I365_MEM_0_OFF_LOW + map*8, offset & 0xff);
0116206 out_reg(socket, I365_MEM_0_OFF_HIGH + map*8,
0116207 ((offset >> 8) & 0x3F) | 0x40);
0116208 out_reg(socket, I365_MAP_ENABLE,
0116209 in_reg(socket, I365_MAP_ENABLE) | I365ME_MEM_MAP_0);
0116210 curr_page= page;
0116211 }
0116212
0116213 /* The following map the PC card's I/O regs to the I/O port of *
0116214 * the computer, then we can control the PC card. *
0116215 * If you want to know the detail, you must reference the PCMCIA *
0116216 * specification. */
0116217 void map_io(int socket, int map, u16_t start, u16_t end, int b16)
0116218 {
0116219 u8_t iow, me;
0116220
0116221 out_reg(socket, I365_IO_0_START_LOW + map*4, start & 0xff);
0116222 out_reg(socket, I365_IO_0_START_HIGH + map*4, start >> 8);
0116223 out_reg(socket, I365_IO_0_END_LOW + map*4, end & 0xff);
0116224 out_reg(socket, I365_IO_0_END_HIGH + map*4, end >> 8);
0116225
0116226 /* Set the I/O window */
0116227 iow= in_reg(socket, I365_IO_WND_CTL);
0116228 iow |= I365IWC_AUTO_SIZE_0 << (map*4);
0116229 if (b16)
0116230 iow |= I365IWC_IO_SIZE_0 << (map*4);
0116231 else
0116232 iow &= ~(I365IWC_IO_SIZE_0 << (map*4));
0116233 out_reg(socket, I365_IO_WND_CTL, iow);
0116234
0116235 /* Enable the map */
0116236 me= in_reg(socket, I365_MAP_ENABLE);
0116237 me |= I365ME_IO_MAP_0 << map;
0116238 out_reg(socket, I365_MAP_ENABLE, me);
0116239 }
0116240
0116241 /* The following read a 8 bits data from the I/O port, if this port *
0116242 * is mapped, the situation is just as we read from the PC card, *
0116243 * PCMCIA control handle it. *
0116244 * If you want to know the detail, you must reference the PCMCIA *
0116245 * specification. */
0116246 u8_t in_reg(int socket, u8_t index)
0116247 {
0116248 index += socket * 0x40;
0116249 outb(index_port, index);
0116250 return inb(index_port+1);
0116251 }
0116252
0116253 /* The following write a 8 bits data to the I/O port, if this port *
0116254 * is mapped, the situation is just as we write to the PC card, *
0116255 * PCMCIA control handle it. *
0116256 * If you want to know the detail, you must reference the PCMCIA *
0116257 * specification. */
0116258 * specification. */
0116259 void out_reg(int socket, u8_t index, u8_t value)
0116260 {
0116261 int i;
0116262 index += socket * 0x40;
0116263 outb(index_port, index);
0116264 outb(index_port+1, value);
0116265 }
0116266
0116267 /*=========================================================================*
0116268 * env_parse *
0116269 *=========================================================================*/
0116270 int env_parse(env, fmt, field, param, min, max)
0116271 char *env; /* environment variable to inspect */
0116272 char *fmt; /* template to parse it with */
0116273 int field; /* field number of value to return */
0116274 long *param; /* address of parameter to get */
0116275 long min, max; /* minimum and maximum values for the parameter */
0116276 {
0116277 /* Parse an environment variable setting, something like "DPETH0=300:3".
0116278 * Panic if the parsing fails. Return EP_UNSET if the environment variable
0116279 * is not set, EP_OFF if it is set to "off", EP_ON if set to "on" or a
0116280 * field is left blank, or EP_SET if a field is given (return value through
0116281 * *param). Punctuation may be used in the environment and format string,
0116282 * fields in the environment string may be empty, and punctuation may be
0116283 * missing to skip fields. The format string contains characters 'd', 'o',
0116284 * 'x' and 'c' to indicate that 10, 8, 16, or 0 is used as the last argument
0116285 * to strtol(). A '*' means that a field should be skipped. If the format
0116286 * string contains something like "4" then the string is repeated 4 characters
0116287 * to the left.
0116288 */
0116289
0116290 char *val, *end;
0116291 long newpar;
0116292 int i = 0, radix, r;
0116293
0116294 val = getenv(env);
0116295
0116296 for (;;) {
0116297 while (*val == ' ') val++;
0116298
0116299 if (*val == 0) return(r); /* the proper exit point */
0116300
0116301 if (*fmt == 0) break; /* too many values */
0116302
0116303 if (strchr(PUNCT, *val) != NULL) {
0116304 /* Time to go to the next field. */
0116305 if (strchr(PUNCT, *fmt) != NULL) i++;
0116306 if (*fmt++ == *val) val++;
0116307 if (*fmt < 32) fmt -= *fmt; /* step back? */
0116308 } else {
0116309 /* Environment contains a value, get it. */
0116310 switch (*fmt) {
0116311 case '*': radix = -1; break;
0116312 case 'd': radix = 10; break;
0116313 case 'o': radix = 010; break;
0116314 case 'x': radix = 0x10; break;
0116315 case 'c': radix = 0; break;
0116316 default: ;
0116317 }
0116318
0116319 if (radix < 0) {
0116320 /* Skip. */
0116321 while (strchr(PUNCT, *val) == NULL) val++;
0116322 continue;
0116323 } else {
0116324 /* A number. */
0116325 newpar = strtol(val, &end, radix);
0116326
0116327 if (end == val) break; /* not a number */
0116328 val = end;
0116329 }
0116330
0116331 if (i == field) {
0116332 /* The field requested. */
0116333 if (newpar < min || newpar > max) break;
0116334 *param = newpar;
0116335 r = EP_SET;
0116336 }
0116337 }
0116338 }
0116339 }
0116340
0116341
0116342
0116343
0116344
0116345
0116346
0116347
0116348
0116349
0116350