112855Sgabeblack@google.com/*****************************************************************************
212855Sgabeblack@google.com
312855Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412855Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
512855Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
612855Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
712855Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
812855Sgabeblack@google.com  License.  You may obtain a copy of the License at
912855Sgabeblack@google.com
1012855Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1112855Sgabeblack@google.com
1212855Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1312855Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1412855Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512855Sgabeblack@google.com  implied.  See the License for the specific language governing
1612855Sgabeblack@google.com  permissions and limitations under the License.
1712855Sgabeblack@google.com
1812855Sgabeblack@google.com *****************************************************************************/
1912855Sgabeblack@google.com
2012855Sgabeblack@google.com/*****************************************************************************
2112855Sgabeblack@google.com
2212855Sgabeblack@google.com  star110089.cpp --
2312855Sgabeblack@google.com
2412855Sgabeblack@google.com  Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
2512855Sgabeblack@google.com
2612855Sgabeblack@google.com *****************************************************************************/
2712855Sgabeblack@google.com
2812855Sgabeblack@google.com/*****************************************************************************
2912855Sgabeblack@google.com
3012855Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3112855Sgabeblack@google.com  changes you are making here.
3212855Sgabeblack@google.com
3312855Sgabeblack@google.com      Name, Affiliation, Date:
3412855Sgabeblack@google.com  Description of Modification:
3512855Sgabeblack@google.com
3612855Sgabeblack@google.com *****************************************************************************/
3712855Sgabeblack@google.com
3812855Sgabeblack@google.com/***********************************************************************
3912855Sgabeblack@google.com
4012855Sgabeblack@google.comThings I had to do to make this work with the SystemC compiler
4112855Sgabeblack@google.com
4212855Sgabeblack@google.comRemove LP_STATS-related #ifdefs
4312855Sgabeblack@google.com
4412855Sgabeblack@google.comAdded SystemC module interface.  Odd function wrapper, wait()s.
4512855Sgabeblack@google.com
4612855Sgabeblack@google.comRemoved use of pointers into lp_table (replaced with array references).
4712855Sgabeblack@google.com
4812855Sgabeblack@google.comGlobal variables are not allowed, so move lp_table into the function.
4912855Sgabeblack@google.com
5012855Sgabeblack@google.comPointers appear to have problems, so comment out test of the "dev" field.
5112855Sgabeblack@google.com
5212855Sgabeblack@google.comThe LP_POLLED macro checks lp_table[minor].dev->port->irq (three dereferences),
5312855Sgabeblack@google.comwhich is not synthesizable.  I replaced it with a constant.
5412855Sgabeblack@google.com
5512855Sgabeblack@google.comw_ctr writes to the control I/O port.  We want to observe this, so added
5612855Sgabeblack@google.coma port to the module, made the function a member function (not just static).
5712855Sgabeblack@google.com
5812855Sgabeblack@google.comWant to observe successive values on the control port, so added a wait() after
5912855Sgabeblack@google.comit is written.
6012855Sgabeblack@google.com
6112855Sgabeblack@google.comAdding the main do loop (there's an if () return statement earlier)
6212855Sgabeblack@google.comgives "WAITs not balanced" errors, even without any wait() statements
6312855Sgabeblack@google.comat all.  Adding them doesn't appear to help (Evidentally, I'm not
6412855Sgabeblack@google.comadding them correctly.)
6512855Sgabeblack@google.com
6612855Sgabeblack@google.comHow to model memory?  Specifically, how to model copy_from_user() and
6712855Sgabeblack@google.comaccesses to buffer memory?  I'll create address, data, and read/write ports
6812855Sgabeblack@google.comfor each memory space, memory access functions that toggle these ports,
6912855Sgabeblack@google.comand finally a replacement for copy_from_user().
7012855Sgabeblack@google.com
7112855Sgabeblack@google.comPointers seem to be broken (BC gives the inscrutable
7212855Sgabeblack@google.com
7312855Sgabeblack@google.com    Error: Width mismatch on port 'n5[1]' of reference to 'group1' in
7412855Sgabeblack@google.com   'lp_write_buf.db:loop_117_design'. (LINK-3)
7512855Sgabeblack@google.com
7612855Sgabeblack@google.comso I'll use a pchar_t type as a replacement.
7712855Sgabeblack@google.com
7812855Sgabeblack@google.comThe const declarations don't work now with typedef unsigned int pchar_t, so
7912855Sgabeblack@google.comI removed them.
8012855Sgabeblack@google.com
8112855Sgabeblack@google.comWas getting "unschedulable" errors until I inserted a few wait() statements.
8212855Sgabeblack@google.com(Very unhelpful diagnostics.)
8312855Sgabeblack@google.com
8412855Sgabeblack@google.comInserting and removing wait()s at will seems to help, but I'm still getting
8512855Sgabeblack@google.comwidth mismatch errors.
8612855Sgabeblack@google.com
8712855Sgabeblack@google.comThe width mismatch errors are due to a SystemC compiler bug.  Adding
8812855Sgabeblack@google.com-Xgroup_idx_logic=0 to the command line eliminates them.
8912855Sgabeblack@google.com
9012855Sgabeblack@google.comMany "mismatched clock" statements appear to be due to the use of nested
9112855Sgabeblack@google.comreturn stataments.  BC doesn't support exits from any more than a single
9212855Sgabeblack@google.comlevel of loop nesting, so whatever hack the SystemC people did is not solid.
9312855Sgabeblack@google.com
9412855Sgabeblack@google.comif statements with a return in one branch seems to cause unsolvable wait
9512855Sgabeblack@google.combalance problems.  I'll rewrite many of them to put the code in the "else"
9612855Sgabeblack@google.combranch.
9712855Sgabeblack@google.com
9812855Sgabeblack@google.comFor if-then with a return within a loop, I appear to need to add an error
9912855Sgabeblack@google.comflag and checks for it.
10012855Sgabeblack@google.com
10112855Sgabeblack@google.comDoing this makes the system schedulable, but even these few lines of code
10212855Sgabeblack@google.comturn into over 1 MB of .db file, take 300MB of core and ten minutes to run.
10312855Sgabeblack@google.comThis corresponds to roughly 140 lines of C code: four conditionals, two
10412855Sgabeblack@google.comnested loops, and one function call.
10512855Sgabeblack@google.com
10612855Sgabeblack@google.com***********************************************************************/
10712855Sgabeblack@google.com
10812855Sgabeblack@google.comtypedef unsigned int pchar_t;
10912855Sgabeblack@google.com
11012855Sgabeblack@google.com/**********************************************************************
11112855Sgabeblack@google.com
11212855Sgabeblack@google.comSystemC-specific things
11312855Sgabeblack@google.com
11412855Sgabeblack@google.com**********************************************************************/
11512855Sgabeblack@google.com
11612855Sgabeblack@google.com#include "systemc.h"
11712855Sgabeblack@google.com
11812855Sgabeblack@google.comSC_MODULE(lp_write_buf) {
11912855Sgabeblack@google.com  sc_in_clk         clk;
12012855Sgabeblack@google.com  sc_in<bool>       reset;
12112855Sgabeblack@google.com  sc_in<unsigned>   minor;
12212855Sgabeblack@google.com  sc_in<unsigned>   buf;   /* a pointer */
12312855Sgabeblack@google.com  sc_in<int>        count;
12412855Sgabeblack@google.com
12512855Sgabeblack@google.com  sc_out<int>       result;       /* return code */
12612855Sgabeblack@google.com  sc_out<bool>      result_ready; /* return flag */
12712855Sgabeblack@google.com
12812855Sgabeblack@google.com  sc_out<char>      control;      /* printer control port */
12912855Sgabeblack@google.com
13012855Sgabeblack@google.com  sc_inout<unsigned>  user_addr;	  /* user memory address */
13112855Sgabeblack@google.com  sc_in<char>       user_read_data; /* user data value */
13212855Sgabeblack@google.com  sc_out<bool>      user_read;    /* user memory read flag */
13312855Sgabeblack@google.com
13412855Sgabeblack@google.com  sc_out<unsigned>  kernel_addr;  /* kernel memory address */
13512855Sgabeblack@google.com  sc_in<char>       kernel_read_data; /* kernel data value */
13612855Sgabeblack@google.com  sc_out<char>      kernel_write_data; /* kernel data value */
13712855Sgabeblack@google.com  sc_out<bool>      kernel_read;
13812855Sgabeblack@google.com  sc_out<bool>      kernel_write;
13912855Sgabeblack@google.com
14012855Sgabeblack@google.com  sc_out<bool>      invalid_read; /* debugging flag: should never be true */
14112855Sgabeblack@google.com
14212855Sgabeblack@google.com  void lp_write_buf_body();
14312855Sgabeblack@google.com  int lp_write_buf_f(unsigned int minor,  pchar_t buf, int count);
14412855Sgabeblack@google.com
14512855Sgabeblack@google.com  /* User and kernel memory operations */
14612855Sgabeblack@google.com  char read_from_user(unsigned a);
14712855Sgabeblack@google.com  char read_from_kernel(unsigned a);
14812855Sgabeblack@google.com  void write_to_kernel(unsigned a, char d);
14912855Sgabeblack@google.com
15012855Sgabeblack@google.com  int copy_from_user(pchar_t,  pchar_t, unsigned long);
15112855Sgabeblack@google.com
15212855Sgabeblack@google.com  /* Output verification */
15312855Sgabeblack@google.com  void check_read_address();
15412855Sgabeblack@google.com
15512855Sgabeblack@google.com  SC_CTOR(lp_write_buf)
15612855Sgabeblack@google.com  {
15712855Sgabeblack@google.com    SC_CTHREAD(lp_write_buf_body, clk.pos());
15812855Sgabeblack@google.com    reset_signal_is(reset,true);
15912855Sgabeblack@google.com    SC_CTHREAD(check_read_address, clk.pos());
16012855Sgabeblack@google.com    reset_signal_is(reset,true);
16112855Sgabeblack@google.com  }
16212855Sgabeblack@google.com};
16312855Sgabeblack@google.com
16412855Sgabeblack@google.comvoid lp_write_buf::check_read_address()
16512855Sgabeblack@google.com{
16612855Sgabeblack@google.com  /* This causes the systemC compiler a fatal internal error */
16712855Sgabeblack@google.com  for (;;) {
16812855Sgabeblack@google.com    invalid_read = user_addr < buf || user_addr >= buf + count;
16912855Sgabeblack@google.com    wait();
17012855Sgabeblack@google.com  }
17112855Sgabeblack@google.com}
17212855Sgabeblack@google.com
17312855Sgabeblack@google.com
17412855Sgabeblack@google.comvoid lp_write_buf::lp_write_buf_body()
17512855Sgabeblack@google.com{
17612855Sgabeblack@google.com  unsigned dummy; /* These three statements compensate for BC weirdness */
17712855Sgabeblack@google.com  dummy = 0;
17812855Sgabeblack@google.com  wait();
17912855Sgabeblack@google.com  for (;;) {
18012855Sgabeblack@google.com    result = 0; result_ready = 0;
18112855Sgabeblack@google.com    unsigned res = lp_write_buf_f(minor, buf, count);
18212855Sgabeblack@google.com    result = (int) res; result_ready = 1;
18312855Sgabeblack@google.com    wait();
18412855Sgabeblack@google.com    result_ready = 0;
18512855Sgabeblack@google.com    wait();
18612855Sgabeblack@google.com  }
18712855Sgabeblack@google.com}
18812855Sgabeblack@google.com
18912855Sgabeblack@google.comchar lp_write_buf::read_from_user(unsigned a)
19012855Sgabeblack@google.com{
19112855Sgabeblack@google.com  char d;
19212855Sgabeblack@google.com  user_addr = a;
19312855Sgabeblack@google.com  user_read = 1;
19412855Sgabeblack@google.com  wait();
19512855Sgabeblack@google.com  d = user_read_data;
19612855Sgabeblack@google.com  user_read = 0;
19712855Sgabeblack@google.com  wait();
19812855Sgabeblack@google.com  return d;
19912855Sgabeblack@google.com}
20012855Sgabeblack@google.com
20112855Sgabeblack@google.comchar lp_write_buf::read_from_kernel(unsigned a)
20212855Sgabeblack@google.com{
20312855Sgabeblack@google.com  char d;
20412855Sgabeblack@google.com  kernel_addr = a;
20512855Sgabeblack@google.com  kernel_read = 1;
20612855Sgabeblack@google.com  wait();
20712855Sgabeblack@google.com  d = kernel_read_data;
20812855Sgabeblack@google.com  kernel_read = 0;
20912855Sgabeblack@google.com  wait();
21012855Sgabeblack@google.com  return d;
21112855Sgabeblack@google.com}
21212855Sgabeblack@google.com
21312855Sgabeblack@google.comvoid lp_write_buf::write_to_kernel(unsigned a, char d)
21412855Sgabeblack@google.com{
21512855Sgabeblack@google.com  kernel_addr = a;
21612855Sgabeblack@google.com  kernel_write_data = d;
21712855Sgabeblack@google.com  kernel_write = 1;
21812855Sgabeblack@google.com  wait();
21912855Sgabeblack@google.com  kernel_write = 0;
22012855Sgabeblack@google.com  wait();
22112855Sgabeblack@google.com}
22212855Sgabeblack@google.com
22312855Sgabeblack@google.comint lp_write_buf::copy_from_user(pchar_t src,  pchar_t dest,
22412855Sgabeblack@google.com				 unsigned long count)
22512855Sgabeblack@google.com{
22612855Sgabeblack@google.com  for ( ; count > 0 ; count--)
22712855Sgabeblack@google.com    write_to_kernel(dest++, read_from_user(src++));
22812855Sgabeblack@google.com  /* What about an error? */
22912855Sgabeblack@google.com  return 0;
23012855Sgabeblack@google.com}
23112855Sgabeblack@google.com
23212855Sgabeblack@google.com/********************************************************************
23312855Sgabeblack@google.com  "Normal" C begins here
23412855Sgabeblack@google.com ********************************************************************/
23512855Sgabeblack@google.com
23612855Sgabeblack@google.com#define	ENXIO		 6	/* No such device or address */
23712855Sgabeblack@google.com#define	EFAULT		14	/* Bad address */
23812855Sgabeblack@google.com
23912855Sgabeblack@google.com// #define NULL             0
24012855Sgabeblack@google.com
24112855Sgabeblack@google.com#define LP_PINTEN	0x10  /* high to read data in or-ed with data out */
24212855Sgabeblack@google.com#define LP_PSELECP	0x08  /* inverted output, active low */
24312855Sgabeblack@google.com#define LP_PINITP	0x04  /* unchanged output, active low */
24412855Sgabeblack@google.com#define LP_PAUTOLF	0x02  /* inverted output, active low */
24512855Sgabeblack@google.com#define LP_PSTROBE	0x01  /* short high output on raising edge */
24612855Sgabeblack@google.com
24712855Sgabeblack@google.com/* #define LP_POLLED(minor) (lp_table[(minor)].dev->port->irq == PARPORT_IRQ_NONE) */
24812855Sgabeblack@google.com#define LP_POLLED(minor) 1
24912855Sgabeblack@google.com
25012855Sgabeblack@google.com#define w_ctr(dev,val) (control = (val))
25112855Sgabeblack@google.com
25212855Sgabeblack@google.com#define LP_NO 3
25312855Sgabeblack@google.com#define LP_BUFFER_SIZE 32
25412855Sgabeblack@google.com
25512855Sgabeblack@google.comstruct lp_struct {
25612855Sgabeblack@google.com  /* struct pardevice *dev; */
25712855Sgabeblack@google.com  pchar_t dev;
25812855Sgabeblack@google.com  unsigned long flags;
25912855Sgabeblack@google.com  unsigned int chars;
26012855Sgabeblack@google.com  unsigned int time;
26112855Sgabeblack@google.com  /*	unsigned int wait; */
26212855Sgabeblack@google.com  pchar_t lp_buffer;
26312855Sgabeblack@google.com  /* struct wait_queue *wait_q; */
26412855Sgabeblack@google.com  unsigned int last_error;
26512855Sgabeblack@google.com  volatile unsigned int irq_detected:1;
26612855Sgabeblack@google.com  volatile unsigned int irq_missed:1;
26712855Sgabeblack@google.com};
26812855Sgabeblack@google.com
26912855Sgabeblack@google.com/* Write count bytes starting at buf in user space to the parallel port
27012855Sgabeblack@google.com   defined by the minor device number */
27112855Sgabeblack@google.com
27212855Sgabeblack@google.comint lp_write_buf::lp_write_buf_f(unsigned int minor,
27312855Sgabeblack@google.com				 pchar_t buf, int count)
27412855Sgabeblack@google.com{
27512855Sgabeblack@google.com  int err;
27612855Sgabeblack@google.com  struct lp_struct lp_table[LP_NO];
27712855Sgabeblack@google.com
27812855Sgabeblack@google.com  /* Added to fake a device */
27912855Sgabeblack@google.com  lp_table[minor].dev = 5;
28012855Sgabeblack@google.com
28112855Sgabeblack@google.com  unsigned long copy_size;
28212855Sgabeblack@google.com  unsigned long total_bytes_written = 0;
28312855Sgabeblack@google.com  unsigned long bytes_written;
28412855Sgabeblack@google.com  /* Removed because pointers are prohibited */
28512855Sgabeblack@google.com  /* struct lp_struct *lp = &lp_table[minor]; */
28612855Sgabeblack@google.com
28712855Sgabeblack@google.com  if (minor >= LP_NO) {
28812855Sgabeblack@google.com    wait();
28912855Sgabeblack@google.com    return -ENXIO;
29012855Sgabeblack@google.com  } else {
29112855Sgabeblack@google.com
29212855Sgabeblack@google.com    /*   if (lp->dev == NULL) */ /* Removed because of a pointer */
29312855Sgabeblack@google.com    /* The following causes a BC error (bad matching width of n15[1]) */
29412855Sgabeblack@google.com    if (lp_table[minor].dev == 0) {
29512855Sgabeblack@google.com      wait();
29612855Sgabeblack@google.com      return -ENXIO;
29712855Sgabeblack@google.com    } else {
29812855Sgabeblack@google.com
29912855Sgabeblack@google.com      lp_table[minor].last_error = 0;
30012855Sgabeblack@google.com      lp_table[minor].irq_detected = 0;
30112855Sgabeblack@google.com      lp_table[minor].irq_missed = 1;
30212855Sgabeblack@google.com
30312855Sgabeblack@google.com      if (LP_POLLED(minor))
30412855Sgabeblack@google.com	w_ctr(minor, LP_PSELECP | LP_PINITP);
30512855Sgabeblack@google.com      else
30612855Sgabeblack@google.com	w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
30712855Sgabeblack@google.com
30812855Sgabeblack@google.com      err = 0;
30912855Sgabeblack@google.com      wait();
31012855Sgabeblack@google.com      do {
31112855Sgabeblack@google.com	wait();
31212855Sgabeblack@google.com	bytes_written = 0;
31312855Sgabeblack@google.com	copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
31412855Sgabeblack@google.com
31512855Sgabeblack@google.com
31612855Sgabeblack@google.com	/* Adding this gives width mismatch errors */
31712855Sgabeblack@google.com	if (copy_from_user(lp_table[minor].lp_buffer, buf, copy_size)) {
31812855Sgabeblack@google.com	  wait();
31912855Sgabeblack@google.com	  w_ctr(minor, LP_PSELECP | LP_PINITP);
32012855Sgabeblack@google.com	  // return -EFAULT;
32112855Sgabeblack@google.com	  err = -EFAULT;
32212855Sgabeblack@google.com	} else {
32312855Sgabeblack@google.com
32412855Sgabeblack@google.com	/** Fake! **/
32512855Sgabeblack@google.com	bytes_written = copy_size;
32612855Sgabeblack@google.com
32712855Sgabeblack@google.com#if 0
32812855Sgabeblack@google.com
32912855Sgabeblack@google.com	while (copy_size) {
33012855Sgabeblack@google.com	  if (lp_char(lp->lp_buffer[bytes_written], minor)) {
33112855Sgabeblack@google.com	    --copy_size;
33212855Sgabeblack@google.com	    ++bytes_written;
33312855Sgabeblack@google.com	  } else {
33412855Sgabeblack@google.com	    int rc = total_bytes_written + bytes_written;
33512855Sgabeblack@google.com
33612855Sgabeblack@google.com
33712855Sgabeblack@google.com	    if (signal_pending(current))
33812855Sgabeblack@google.com	      {
33912855Sgabeblack@google.com		w_ctr(minor, LP_PSELECP | LP_PINITP);
34012855Sgabeblack@google.com		if (total_bytes_written + bytes_written)
34112855Sgabeblack@google.com		  return total_bytes_written + bytes_written;
34212855Sgabeblack@google.com		else
34312855Sgabeblack@google.com		  return -EINTR;
34412855Sgabeblack@google.com	      }
34512855Sgabeblack@google.com
34612855Sgabeblack@google.com	    if (lp_check_status(minor))
34712855Sgabeblack@google.com	      {
34812855Sgabeblack@google.com		w_ctr(minor, LP_PSELECP | LP_PINITP);
34912855Sgabeblack@google.com		return rc ? rc : -EIO;
35012855Sgabeblack@google.com	      }
35112855Sgabeblack@google.com
35212855Sgabeblack@google.com	    if (LP_POLLED(minor) ||
35312855Sgabeblack@google.com		lp_table[minor].irq_missed)
35412855Sgabeblack@google.com	      {
35512855Sgabeblack@google.com	      lp_polling:
35612855Sgabeblack@google.com		current->state = TASK_INTERRUPTIBLE;
35712855Sgabeblack@google.com		lp_schedule(minor, LP_TIME(minor));
35812855Sgabeblack@google.com	      } else {
35912855Sgabeblack@google.com		cli();
36012855Sgabeblack@google.com		if (LP_PREEMPTED(minor))
36112855Sgabeblack@google.com		  {
36212855Sgabeblack@google.com		    /*
36312855Sgabeblack@google.com		     * We can' t sleep on the interrupt
36412855Sgabeblack@google.com		     * since another pardevice need the port.
36512855Sgabeblack@google.com		     * We must check this in a cli() protected
36612855Sgabeblack@google.com		     * envinroment to avoid parport sharing
36712855Sgabeblack@google.com		     * starvation.
36812855Sgabeblack@google.com		     */
36912855Sgabeblack@google.com		    sti();
37012855Sgabeblack@google.com		    goto lp_polling;
37112855Sgabeblack@google.com		  }
37212855Sgabeblack@google.com		if (!lp_table[minor].irq_detected)
37312855Sgabeblack@google.com		  interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT);
37412855Sgabeblack@google.com		sti();
37512855Sgabeblack@google.com	      }
37612855Sgabeblack@google.com	  }
37712855Sgabeblack@google.com	}
37812855Sgabeblack@google.com
37912855Sgabeblack@google.com#endif
38012855Sgabeblack@google.com
38112855Sgabeblack@google.com	total_bytes_written += bytes_written;
38212855Sgabeblack@google.com	buf += bytes_written;
38312855Sgabeblack@google.com	count -= bytes_written;
38412855Sgabeblack@google.com
38512855Sgabeblack@google.com	wait();
38612855Sgabeblack@google.com	}
38712855Sgabeblack@google.com
38812855Sgabeblack@google.com      } while (count > 0 && err >= 0);
38912855Sgabeblack@google.com
39012855Sgabeblack@google.com      wait();
39112855Sgabeblack@google.com
39212855Sgabeblack@google.com      if (err >= 0 ) {
39312855Sgabeblack@google.com
39412855Sgabeblack@google.com	w_ctr(minor, LP_PSELECP | LP_PINITP);
39512855Sgabeblack@google.com	return total_bytes_written;
39612855Sgabeblack@google.com      } else {
39712855Sgabeblack@google.com	return err;
39812855Sgabeblack@google.com      }
39912855Sgabeblack@google.com
40012855Sgabeblack@google.com    }
40112855Sgabeblack@google.com  }
40212855Sgabeblack@google.com}
40312855Sgabeblack@google.com
404