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